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.
+
+
+///////////////////////////////////////////////////////////////////////////
+tinyexr contains some OpenEXR code, which is licensed as follows.
+Note that OpenEXR had joined Academy Software Foudation projects in 2019.
+The latest code of OpenEXR can be found in
+https://github.com/AcademySoftwareFoundation/openexr .
+///////////////////////////////////////////////////////////////////////////
+OpenEXR
+
+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.
+
diff --git a/stuff/doc/español/particlesFx.html b/stuff/doc/español/particlesFx.html
index c8c77686..e1f006cc 100644
--- a/stuff/doc/español/particlesFx.html
+++ b/stuff/doc/español/particlesFx.html
@@ -599,25 +599,6 @@ rt
○ |
-
- |
- Trail |
- Trail |
- Muestra una estela para cada partícula, que se desvanecerá a lo largo de la cantidad de fotogramas especificados en el parámetro Trail. |
- ― |
-
-
- |
- |
- Step |
- Permite definir cuántas imágenes se mostrarán en la estela. Cada estela estará compuesta por (Trail/Step) imágenes. |
- ― |
-
|
Lifetime |
@@ -855,6 +836,43 @@ rt
― |
+
+ |
+ Trail |
+ Trail |
+ Muestra una estela para cada partícula, que se desvanecerá a lo largo de la cantidad de fotogramas especificados en el parámetro Trail. |
+ ― |
+
+
+ |
+ |
+ Step |
+ Permite definir cuántas imágenes se mostrarán en la estela. Cada estela estará compuesta por (Trail/Step) imágenes. |
+ ― |
+
+
+ |
+ |
+ Motion Blur |
+ When turned ON, particles will be rendered with motion blur according to its movement. |
+ ― |
+
+
+ |
+ |
+ Gamma |
+ Film gamma value used for the motion blur. |
+ ― |
+
|
○ |
-
- |
- Trail |
- Trail |
- Display a trail for each particle, that fades out over the number of frames specified in the Trail parameter. |
- ― |
-
-
- |
- |
- Step |
- The particle trail will be displayed every Step value. That is, there will be (Trail/Step) images displayed in the trail. |
- ― |
-
|
Lifetime |
@@ -849,7 +830,44 @@ rt
Trail
Opacity |
When a trail is defined in Birth Params → Trail, it specifies the minimum / maximum values for the opacity of the particles in the trail. |
+ width:356pt'>When a trail is defined in Animation → Trail, it specifies the minimum / maximum values for the opacity of the particles in the trail.
+ ― |
+
+
+ |
+ Trail |
+ Trail |
+ Display a trail for each particle, that fades out over the number of frames specified in the Trail parameter. |
+ ― |
+
+
+ |
+ |
+ Step |
+ The particle trail will be displayed every Step value. That is, there will be (Trail/Step) images displayed in the trail. |
+ ― |
+
+
+ |
+ |
+ Motion Blur |
+ When turned ON, particles will be rendered with motion blur according to its movement. |
+ ― |
+
+
+ |
+ |
+ Gamma |
+ Film gamma value used for the motion blur. |
― |
diff --git a/stuff/doc/日本語/particlesFx.html b/stuff/doc/日本語/particlesFx.html
index 28ddffdc..15efa836 100644
--- a/stuff/doc/日本語/particlesFx.html
+++ b/stuff/doc/日本語/particlesFx.html
@@ -599,25 +599,6 @@ rt
|
-
- @ |
- Trail |
- Trail |
- OՂ\BTrailŎw肵t[ătF[hAEgB |
- \ |
-
-
- @ |
- @ |
- Step |
- OՂSteplɕ\BȂ킿AOՂ̉摜́iTrailj/(Frame)\邱ƂɂȂB |
- \ |
-
@ |
Lifetime |
@@ -855,7 +836,44 @@ rt
Trail
Opacity |
BirthParamTrailTrailw肵ƂA̋OՂ̃p[eBN̕sx̍ŏ/ől߂B |
+ width:356pt'>AnimationTrailTrailw肵ƂA̋OՂ̃p[eBN̕sx̍ŏ/ől߂B
+ \ |
+
+
+ @ |
+ Trail |
+ Trail |
+ OՂ\BTrailŎw肵t[ătF[hAEgB |
+ \ |
+
+
+ @ |
+ @ |
+ Step |
+ OՂSteplɕ\BȂ킿AOՂ̉摜́iTrailj/(Frame)\邱ƂɂȂB |
+ \ |
+
+
+ @ |
+ @ |
+ Motion Blur |
+ When turned ON, particles will be rendered with motion blur according to its movement. |
+ \ |
+
+
+ @ |
+ @ |
+ Gamma |
+ Film gamma value used for the motion blur. |
\ |
diff --git a/stuff/library/custom panel templates/drawing toolbox.ui b/stuff/library/custom panel templates/drawing toolbox.ui
new file mode 100644
index 00000000..a8fd7723
--- /dev/null
+++ b/stuff/library/custom panel templates/drawing toolbox.ui
@@ -0,0 +1,362 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 127
+ 516
+
+
+
+
+ 0
+ 0
+
+
+
+ Form
+
+
+
+ 15
+
+
+ QLayout::SetDefaultConstraint
+
+ -
+
+
+ 5
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 90
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Btn1
+
+
+
+ 40
+ 40
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 90
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Btn2
+
+
+
+ 40
+ 40
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 90
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Btn3
+
+
+
+ 40
+ 40
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 90
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Btn4
+
+
+
+ 40
+ 40
+
+
+
+
+
+
+ -
+
+
+ 5
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 90
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Btn5
+
+
+
+ 40
+ 40
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 90
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Btn6
+
+
+
+ 40
+ 40
+
+
+
+
+
+
+ -
+
+
+ 5
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 105
+ 90
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Btn7
+
+
+
+ 40
+ 40
+
+
+
+
+ -
+
+
+ 5
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 40
+ 90
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Btn8
+
+
+
+ 30
+ 30
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 15
+ 90
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 40
+ 90
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ Btn9
+
+
+
+ 30
+ 30
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/stuff/library/custom panel templates/eight buttons.ui b/stuff/library/custom panel templates/eight buttons.ui
new file mode 100644
index 00000000..043b62ad
--- /dev/null
+++ b/stuff/library/custom panel templates/eight buttons.ui
@@ -0,0 +1,221 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 236
+ 124
+
+
+
+ Form
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 50
+
+
+
+ Btn2
+
+
+
+ 20
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 50
+
+
+
+ Btn1
+
+
+
+ 20
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 50
+
+
+
+ Btn4
+
+
+
+ 20
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 50
+
+
+
+ Btn3
+
+
+
+ 20
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 50
+
+
+
+ Btn5
+
+
+
+ 20
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 50
+
+
+
+ Btn6
+
+
+
+ 20
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 50
+
+
+
+ Btn7
+
+
+
+ 20
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 50
+
+
+
+ Btn8
+
+
+
+ 20
+ 20
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/stuff/library/shaders/programs/HSLBlendGPU.frag b/stuff/library/shaders/programs/HSLBlendGPU.frag
index 070ad7e6..2061a859 100644
--- a/stuff/library/shaders/programs/HSLBlendGPU.frag
+++ b/stuff/library/shaders/programs/HSLBlendGPU.frag
@@ -95,7 +95,7 @@ void main( void )
vec4 fg_frag = texture2D(inputImage[0], fg_texPos);
vec4 bg_frag = texture2D(inputImage[1], bg_texPos);
- // De-premultiplication
+ // De-premultiplication of textures
vec3 fg_pix = vec3(0.0);
if (fg_frag.a > 0.0) fg_pix = fg_frag.rgb / fg_frag.a;
vec3 bg_pix = vec3(0.0);
@@ -107,20 +107,12 @@ void main( void )
if (bmask) {
gl_FragColor.a = bg_alpha;
} else {
- gl_FragColor.a = fg_alpha + bg_alpha * (1.0 - fg_alpha);
+ gl_FragColor.a = bg_alpha + fg_alpha * (1.0 - bg_alpha);
}
if (gl_FragColor.a <= 0.0) discard;
-
- // Perform blending
- if (fg_alpha > 0.0 && bg_alpha > 0.0) {
- vec3 o_pix = SetLumSat(bhue ? fg_pix : bg_pix, bsat ? fg_pix : bg_pix, blum ? fg_pix : bg_pix);
- gl_FragColor.rgb = mix(bg_pix, o_pix, balpha);
- } else if (fg_alpha > 0.0) {
- gl_FragColor.rgb = fg_pix;
- } else {
- gl_FragColor.rgb = bg_pix;
- }
- // Premultiplication
- gl_FragColor.rgb *= gl_FragColor.a;
+ // Perform blending
+ vec3 o_pix = SetLumSat(bhue ? fg_pix : bg_pix, bsat ? fg_pix : bg_pix, blum ? fg_pix : bg_pix);
+ vec3 b_pix = bmask ? vec3(0.0) : fg_pix;
+ gl_FragColor.rgb = bg_pix * bg_alpha * (1.0 - fg_alpha) + mix(b_pix, o_pix, bg_alpha) * fg_alpha;
}
diff --git a/stuff/library/textures/Denim2_s.bmp b/stuff/library/textures/Denim2_s.bmp
new file mode 100644
index 00000000..6cfd5775
Binary files /dev/null and b/stuff/library/textures/Denim2_s.bmp differ
diff --git a/stuff/library/textures/Knit_s.bmp b/stuff/library/textures/Knit_s.bmp
new file mode 100644
index 00000000..97fa5baf
Binary files /dev/null and b/stuff/library/textures/Knit_s.bmp differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0001.png b/stuff/library/textures/brush tips/dry_brush.0001.png
new file mode 100644
index 00000000..2f37ed55
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0001.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0002.png b/stuff/library/textures/brush tips/dry_brush.0002.png
new file mode 100644
index 00000000..e41dd2b8
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0002.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0003.png b/stuff/library/textures/brush tips/dry_brush.0003.png
new file mode 100644
index 00000000..6471cbac
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0003.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0004.png b/stuff/library/textures/brush tips/dry_brush.0004.png
new file mode 100644
index 00000000..9325baa8
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0004.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0005.png b/stuff/library/textures/brush tips/dry_brush.0005.png
new file mode 100644
index 00000000..45271558
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0005.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0006.png b/stuff/library/textures/brush tips/dry_brush.0006.png
new file mode 100644
index 00000000..9cfc1158
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0006.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0007.png b/stuff/library/textures/brush tips/dry_brush.0007.png
new file mode 100644
index 00000000..b7e60b17
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0007.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0008.png b/stuff/library/textures/brush tips/dry_brush.0008.png
new file mode 100644
index 00000000..b9d732e1
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0008.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0009.png b/stuff/library/textures/brush tips/dry_brush.0009.png
new file mode 100644
index 00000000..2c8e93ee
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0009.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0010.png b/stuff/library/textures/brush tips/dry_brush.0010.png
new file mode 100644
index 00000000..54b58227
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0010.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0011.png b/stuff/library/textures/brush tips/dry_brush.0011.png
new file mode 100644
index 00000000..972ba977
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0011.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0012.png b/stuff/library/textures/brush tips/dry_brush.0012.png
new file mode 100644
index 00000000..424e9153
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0012.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0013.png b/stuff/library/textures/brush tips/dry_brush.0013.png
new file mode 100644
index 00000000..cd4e38f9
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0013.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0014.png b/stuff/library/textures/brush tips/dry_brush.0014.png
new file mode 100644
index 00000000..efaacba0
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0014.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0015.png b/stuff/library/textures/brush tips/dry_brush.0015.png
new file mode 100644
index 00000000..be012dd6
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0015.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0016.png b/stuff/library/textures/brush tips/dry_brush.0016.png
new file mode 100644
index 00000000..bf91dab3
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0016.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0017.png b/stuff/library/textures/brush tips/dry_brush.0017.png
new file mode 100644
index 00000000..41f41aa8
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0017.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0018.png b/stuff/library/textures/brush tips/dry_brush.0018.png
new file mode 100644
index 00000000..3edce292
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0018.png differ
diff --git a/stuff/library/textures/brush tips/dry_brush.0019.png b/stuff/library/textures/brush tips/dry_brush.0019.png
new file mode 100644
index 00000000..a6ab20f7
Binary files /dev/null and b/stuff/library/textures/brush tips/dry_brush.0019.png differ
diff --git a/stuff/library/textures/brush tips/fluffy.0001.png b/stuff/library/textures/brush tips/fluffy.0001.png
new file mode 100644
index 00000000..e05568d9
Binary files /dev/null and b/stuff/library/textures/brush tips/fluffy.0001.png differ
diff --git a/stuff/library/textures/brush tips/fluffy.0002.png b/stuff/library/textures/brush tips/fluffy.0002.png
new file mode 100644
index 00000000..8e7f62e2
Binary files /dev/null and b/stuff/library/textures/brush tips/fluffy.0002.png differ
diff --git a/stuff/library/textures/brush tips/fluffy.0003.png b/stuff/library/textures/brush tips/fluffy.0003.png
new file mode 100644
index 00000000..9706411e
Binary files /dev/null and b/stuff/library/textures/brush tips/fluffy.0003.png differ
diff --git a/stuff/library/textures/brush tips/fluffy.0004.png b/stuff/library/textures/brush tips/fluffy.0004.png
new file mode 100644
index 00000000..3c8f19ae
Binary files /dev/null and b/stuff/library/textures/brush tips/fluffy.0004.png differ
diff --git a/stuff/library/textures/brush tips/fluffy.0005.png b/stuff/library/textures/brush tips/fluffy.0005.png
new file mode 100644
index 00000000..a151346a
Binary files /dev/null and b/stuff/library/textures/brush tips/fluffy.0005.png differ
diff --git a/stuff/library/textures/brush tips/fluffy.0006.png b/stuff/library/textures/brush tips/fluffy.0006.png
new file mode 100644
index 00000000..076e227a
Binary files /dev/null and b/stuff/library/textures/brush tips/fluffy.0006.png differ
diff --git a/stuff/library/textures/brush tips/fluffy.0007.png b/stuff/library/textures/brush tips/fluffy.0007.png
new file mode 100644
index 00000000..cc00c7a4
Binary files /dev/null and b/stuff/library/textures/brush tips/fluffy.0007.png differ
diff --git a/stuff/library/textures/brush tips/single_line.0001.png b/stuff/library/textures/brush tips/single_line.0001.png
new file mode 100644
index 00000000..0f40e8c5
Binary files /dev/null and b/stuff/library/textures/brush tips/single_line.0001.png differ
diff --git a/stuff/library/textures/brush tips/single_line.0002.png b/stuff/library/textures/brush tips/single_line.0002.png
new file mode 100644
index 00000000..609a5750
Binary files /dev/null and b/stuff/library/textures/brush tips/single_line.0002.png differ
diff --git a/stuff/library/textures/brush tips/single_line.0003.png b/stuff/library/textures/brush tips/single_line.0003.png
new file mode 100644
index 00000000..6b57ff07
Binary files /dev/null and b/stuff/library/textures/brush tips/single_line.0003.png differ
diff --git a/stuff/library/textures/brush tips/single_line.0004.png b/stuff/library/textures/brush tips/single_line.0004.png
new file mode 100644
index 00000000..c2e4fb3d
Binary files /dev/null and b/stuff/library/textures/brush tips/single_line.0004.png differ
diff --git a/stuff/library/textures/brush tips/single_line.0005.png b/stuff/library/textures/brush tips/single_line.0005.png
new file mode 100644
index 00000000..faaeb1ee
Binary files /dev/null and b/stuff/library/textures/brush tips/single_line.0005.png differ
diff --git a/stuff/library/textures/brush tips/single_line.0006.png b/stuff/library/textures/brush tips/single_line.0006.png
new file mode 100644
index 00000000..921de427
Binary files /dev/null and b/stuff/library/textures/brush tips/single_line.0006.png differ
diff --git a/stuff/library/textures/brush tips/single_line.0007.png b/stuff/library/textures/brush tips/single_line.0007.png
new file mode 100644
index 00000000..9c3b1105
Binary files /dev/null and b/stuff/library/textures/brush tips/single_line.0007.png differ
diff --git a/stuff/library/textures/brush tips/single_line.0008.png b/stuff/library/textures/brush tips/single_line.0008.png
new file mode 100644
index 00000000..9614aac8
Binary files /dev/null and b/stuff/library/textures/brush tips/single_line.0008.png differ
diff --git a/stuff/library/textures/brush tips/single_line.0009.png b/stuff/library/textures/brush tips/single_line.0009.png
new file mode 100644
index 00000000..639df940
Binary files /dev/null and b/stuff/library/textures/brush tips/single_line.0009.png differ
diff --git a/stuff/library/textures/brush tips/single_line.0010.png b/stuff/library/textures/brush tips/single_line.0010.png
new file mode 100644
index 00000000..e33798b2
Binary files /dev/null and b/stuff/library/textures/brush tips/single_line.0010.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0001.png b/stuff/library/textures/brush tips/streaky.0001.png
new file mode 100644
index 00000000..5d60f30e
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0001.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0002.png b/stuff/library/textures/brush tips/streaky.0002.png
new file mode 100644
index 00000000..714c178e
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0002.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0003.png b/stuff/library/textures/brush tips/streaky.0003.png
new file mode 100644
index 00000000..de24bf71
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0003.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0004.png b/stuff/library/textures/brush tips/streaky.0004.png
new file mode 100644
index 00000000..84e92aee
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0004.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0005.png b/stuff/library/textures/brush tips/streaky.0005.png
new file mode 100644
index 00000000..a1353617
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0005.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0006.png b/stuff/library/textures/brush tips/streaky.0006.png
new file mode 100644
index 00000000..db9dcb48
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0006.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0007.png b/stuff/library/textures/brush tips/streaky.0007.png
new file mode 100644
index 00000000..7696e86d
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0007.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0008.png b/stuff/library/textures/brush tips/streaky.0008.png
new file mode 100644
index 00000000..f7a225e9
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0008.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0009.png b/stuff/library/textures/brush tips/streaky.0009.png
new file mode 100644
index 00000000..fcace4d6
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0009.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0010.png b/stuff/library/textures/brush tips/streaky.0010.png
new file mode 100644
index 00000000..ae27928b
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0010.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0011.png b/stuff/library/textures/brush tips/streaky.0011.png
new file mode 100644
index 00000000..d70585c3
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0011.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0012.png b/stuff/library/textures/brush tips/streaky.0012.png
new file mode 100644
index 00000000..bc8aee0f
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0012.png differ
diff --git a/stuff/library/textures/brush tips/streaky.0013.png b/stuff/library/textures/brush tips/streaky.0013.png
new file mode 100644
index 00000000..16070ec7
Binary files /dev/null and b/stuff/library/textures/brush tips/streaky.0013.png differ
diff --git a/stuff/library/textures/brush tips/thick.0001.png b/stuff/library/textures/brush tips/thick.0001.png
new file mode 100644
index 00000000..01779c0d
Binary files /dev/null and b/stuff/library/textures/brush tips/thick.0001.png differ
diff --git a/stuff/library/textures/brush tips/thick.0002.png b/stuff/library/textures/brush tips/thick.0002.png
new file mode 100644
index 00000000..38d0cc32
Binary files /dev/null and b/stuff/library/textures/brush tips/thick.0002.png differ
diff --git a/stuff/library/textures/brush tips/thick.0003.png b/stuff/library/textures/brush tips/thick.0003.png
new file mode 100644
index 00000000..1a1b7078
Binary files /dev/null and b/stuff/library/textures/brush tips/thick.0003.png differ
diff --git a/stuff/library/textures/brush tips/thick.0004.png b/stuff/library/textures/brush tips/thick.0004.png
new file mode 100644
index 00000000..c9efb79f
Binary files /dev/null and b/stuff/library/textures/brush tips/thick.0004.png differ
diff --git a/stuff/library/textures/brush tips/thick.0005.png b/stuff/library/textures/brush tips/thick.0005.png
new file mode 100644
index 00000000..f30c4173
Binary files /dev/null and b/stuff/library/textures/brush tips/thick.0005.png differ
diff --git a/stuff/library/textures/brush tips/thick.0006.png b/stuff/library/textures/brush tips/thick.0006.png
new file mode 100644
index 00000000..c304354b
Binary files /dev/null and b/stuff/library/textures/brush tips/thick.0006.png differ
diff --git a/stuff/library/textures/brush tips/thick.0007.png b/stuff/library/textures/brush tips/thick.0007.png
new file mode 100644
index 00000000..817e0b6d
Binary files /dev/null and b/stuff/library/textures/brush tips/thick.0007.png differ
diff --git a/stuff/library/textures/brush tips/thick.0008.png b/stuff/library/textures/brush tips/thick.0008.png
new file mode 100644
index 00000000..b3314924
Binary files /dev/null and b/stuff/library/textures/brush tips/thick.0008.png differ
diff --git a/stuff/library/textures/brush tips/thick.0009.png b/stuff/library/textures/brush tips/thick.0009.png
new file mode 100644
index 00000000..85b9b43a
Binary files /dev/null and b/stuff/library/textures/brush tips/thick.0009.png differ
diff --git a/stuff/library/textures/brush tips/thick.0010.png b/stuff/library/textures/brush tips/thick.0010.png
new file mode 100644
index 00000000..4539a039
Binary files /dev/null and b/stuff/library/textures/brush tips/thick.0010.png differ
diff --git a/stuff/library/textures/papercrump.bmp b/stuff/library/textures/papercrump.bmp
index 7b6f0399..7f22a3e2 100644
Binary files a/stuff/library/textures/papercrump.bmp and b/stuff/library/textures/papercrump.bmp differ
diff --git a/stuff/library/textures/snakeskin.bmp b/stuff/library/textures/snakeskin.bmp
new file mode 100644
index 00000000..65321c7f
Binary files /dev/null and b/stuff/library/textures/snakeskin.bmp differ
diff --git a/stuff/library/textures/snakeskinred.bmp b/stuff/library/textures/snakeskinred.bmp
new file mode 100644
index 00000000..eff6ec7b
Binary files /dev/null and b/stuff/library/textures/snakeskinred.bmp differ
diff --git a/stuff/library/textures/snow.bmp b/stuff/library/textures/snow.bmp
new file mode 100644
index 00000000..204665ee
Binary files /dev/null and b/stuff/library/textures/snow.bmp differ
diff --git a/stuff/library/textures/wornleather.bmp b/stuff/library/textures/wornleather.bmp
new file mode 100644
index 00000000..8ad5a5e8
Binary files /dev/null and b/stuff/library/textures/wornleather.bmp differ
diff --git a/stuff/profiles/layouts/fxs/STD_inoAddFx.xml b/stuff/profiles/layouts/fxs/STD_inoAddFx.xml
index dcb99ab3..09214178 100644
--- a/stuff/profiles/layouts/fxs/STD_inoAddFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoAddFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoColorBurnFx.xml b/stuff/profiles/layouts/fxs/STD_inoColorBurnFx.xml
index 6073f3c5..66b2dffb 100644
--- a/stuff/profiles/layouts/fxs/STD_inoColorBurnFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoColorBurnFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoColorDodgeFx.xml b/stuff/profiles/layouts/fxs/STD_inoColorDodgeFx.xml
index 3d4e87df..8e36f068 100644
--- a/stuff/profiles/layouts/fxs/STD_inoColorDodgeFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoColorDodgeFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoCrossDissolveFx.xml b/stuff/profiles/layouts/fxs/STD_inoCrossDissolveFx.xml
index 171b7395..d65ab81f 100644
--- a/stuff/profiles/layouts/fxs/STD_inoCrossDissolveFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoCrossDissolveFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoDarkenFx.xml b/stuff/profiles/layouts/fxs/STD_inoDarkenFx.xml
index 8041df33..77d29ec0 100644
--- a/stuff/profiles/layouts/fxs/STD_inoDarkenFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoDarkenFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoDarkerColorFx.xml b/stuff/profiles/layouts/fxs/STD_inoDarkerColorFx.xml
index 358c5a06..21dee73d 100644
--- a/stuff/profiles/layouts/fxs/STD_inoDarkerColorFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoDarkerColorFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoDivideFx.xml b/stuff/profiles/layouts/fxs/STD_inoDivideFx.xml
index 42eaca07..211d97a2 100644
--- a/stuff/profiles/layouts/fxs/STD_inoDivideFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoDivideFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoHardLightFx.xml b/stuff/profiles/layouts/fxs/STD_inoHardLightFx.xml
index 8b822ef4..21bb3e64 100644
--- a/stuff/profiles/layouts/fxs/STD_inoHardLightFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoHardLightFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoHardMixFx.xml b/stuff/profiles/layouts/fxs/STD_inoHardMixFx.xml
index c69b3928..f157ee32 100644
--- a/stuff/profiles/layouts/fxs/STD_inoHardMixFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoHardMixFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoLightenFx.xml b/stuff/profiles/layouts/fxs/STD_inoLightenFx.xml
index 6c6a7600..08362045 100644
--- a/stuff/profiles/layouts/fxs/STD_inoLightenFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoLightenFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoLighterColorFx.xml b/stuff/profiles/layouts/fxs/STD_inoLighterColorFx.xml
index a143e51d..5d33ebdc 100644
--- a/stuff/profiles/layouts/fxs/STD_inoLighterColorFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoLighterColorFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoLinearBurnFx.xml b/stuff/profiles/layouts/fxs/STD_inoLinearBurnFx.xml
index ed64746a..47c2d8aa 100644
--- a/stuff/profiles/layouts/fxs/STD_inoLinearBurnFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoLinearBurnFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoLinearDodgeFx.xml b/stuff/profiles/layouts/fxs/STD_inoLinearDodgeFx.xml
index 70f34a5b..00f49896 100644
--- a/stuff/profiles/layouts/fxs/STD_inoLinearDodgeFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoLinearDodgeFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoLinearLightFx.xml b/stuff/profiles/layouts/fxs/STD_inoLinearLightFx.xml
index 303bd46c..8e314671 100644
--- a/stuff/profiles/layouts/fxs/STD_inoLinearLightFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoLinearLightFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoMultiplyFx.xml b/stuff/profiles/layouts/fxs/STD_inoMultiplyFx.xml
index 5064564c..1be34087 100644
--- a/stuff/profiles/layouts/fxs/STD_inoMultiplyFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoMultiplyFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoOverFx.xml b/stuff/profiles/layouts/fxs/STD_inoOverFx.xml
index 5d3f173e..5d5b2d5b 100644
--- a/stuff/profiles/layouts/fxs/STD_inoOverFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoOverFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoOverlayFx.xml b/stuff/profiles/layouts/fxs/STD_inoOverlayFx.xml
index d87c028e..244216e1 100644
--- a/stuff/profiles/layouts/fxs/STD_inoOverlayFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoOverlayFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoPinLightFx.xml b/stuff/profiles/layouts/fxs/STD_inoPinLightFx.xml
index d8332df0..62de5e29 100644
--- a/stuff/profiles/layouts/fxs/STD_inoPinLightFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoPinLightFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoScreenFx.xml b/stuff/profiles/layouts/fxs/STD_inoScreenFx.xml
index 5e301a89..733b2185 100644
--- a/stuff/profiles/layouts/fxs/STD_inoScreenFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoScreenFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoSoftLightFx.xml b/stuff/profiles/layouts/fxs/STD_inoSoftLightFx.xml
index 416be102..ff6f6604 100644
--- a/stuff/profiles/layouts/fxs/STD_inoSoftLightFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoSoftLightFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoSubtractFx.xml b/stuff/profiles/layouts/fxs/STD_inoSubtractFx.xml
index 4922cf04..3ce1166f 100644
--- a/stuff/profiles/layouts/fxs/STD_inoSubtractFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoSubtractFx.xml
@@ -4,9 +4,10 @@
clipping_mask
alpha_rendering
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_inoVividLightFx.xml b/stuff/profiles/layouts/fxs/STD_inoVividLightFx.xml
index 12eb439c..24c07994 100644
--- a/stuff/profiles/layouts/fxs/STD_inoVividLightFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_inoVividLightFx.xml
@@ -3,9 +3,10 @@
opacity
clipping_mask
- linear
-
+ colorSpaceMode
+
gamma
+ gammaAdjust
premultiplied
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_AdjustExposureFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_AdjustExposureFx.xml
index 71170ef3..a3056f7f 100644
--- a/stuff/profiles/layouts/fxs/STD_iwa_AdjustExposureFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_iwa_AdjustExposureFx.xml
@@ -1,6 +1,8 @@
hardness
+ gamma
+ gammaAdjust
scale
offset
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_BloomFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_BloomFx.xml
index f6c57bff..e34a6a3d 100644
--- a/stuff/profiles/layouts/fxs/STD_iwa_BloomFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_iwa_BloomFx.xml
@@ -1,6 +1,7 @@
gamma
+ gammaAdjust
auto_gain
gain_adjust
gain
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_BokehAdvancedFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_BokehAdvancedFx.xml
index 473f9e48..e355c1cf 100644
--- a/stuff/profiles/layouts/fxs/STD_iwa_BokehAdvancedFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_iwa_BokehAdvancedFx.xml
@@ -1,49 +1,106 @@
-
+
on_focus_distance
bokeh_amount
- masterHardness
+ linearizeMode
+
+ masterHardness
+
+
+ masterGamma
+ masterGammaAdjust
+
hardnessPerSource
distance1
bokeh_adjustment1
- hardness1
- depth_ref1
+
+ hardness1
+
+
+ gamma1
+ gammaAdjust1
+
+
+ depth_ref1
+ fillGap1
+ doMedian1
+
depthRange1
distance2
bokeh_adjustment2
- hardness2
- depth_ref2
+
+ hardness2
+
+
+ gamma2
+ gammaAdjust2
+
+
+ depth_ref2
+ fillGap2
+ doMedian2
+
depthRange2
distance3
bokeh_adjustment3
- hardness3
- depth_ref3
+
+ hardness3
+
+
+ gamma3
+ gammaAdjust3
+
+
+ depth_ref3
+ fillGap3
+ doMedian3
+
depthRange3
distance4
bokeh_adjustment4
- hardness4
- depth_ref4
+
+ hardness4
+
+
+ gamma4
+ gammaAdjust4
+
+
+ depth_ref4
+ fillGap4
+ doMedian4
+
depthRange4
distance5
bokeh_adjustment5
- hardness5
- depth_ref5
+
+ hardness5
+
+
+ gamma5
+ gammaAdjust5
+
+
+ depth_ref5
+ fillGap5
+ doMedian5
+
depthRange5
@@ -54,7 +111,38 @@
hardness3
hardness4
hardness5
+ gamma1
+ gamma2
+ gamma3
+ gamma4
+ gamma5
+ gammaAdjust1
+ gammaAdjust2
+ gammaAdjust3
+ gammaAdjust4
+ gammaAdjust5
+
+
+ fillGap1
+ doMedian1
+
+
+ fillGap2
+ doMedian2
+
+
+ fillGap3
+ doMedian3
+
+
+ fillGap4
+ doMedian4
+
+
+ fillGap5
+ doMedian5
+
-
\ No newline at end of file
+
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_BokehFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_BokehFx.xml
index e5c7a8cc..c9716df9 100644
--- a/stuff/profiles/layouts/fxs/STD_iwa_BokehFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_iwa_BokehFx.xml
@@ -3,8 +3,15 @@
on_focus_distance
bokeh_amount
+ linearizeMode
+
hardness
-
+
+
+ gamma
+ gammaAdjust
+
+
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_BokehRefFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_BokehRefFx.xml
index 6df0b34f..2e30573d 100644
--- a/stuff/profiles/layouts/fxs/STD_iwa_BokehRefFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_iwa_BokehRefFx.xml
@@ -3,7 +3,14 @@
on_focus_distance
bokeh_amount
- hardness
+ linearizeMode
+
+ hardness
+
+
+ gamma
+ gammaAdjust
+
distance_precision
fill_gap
fill_gap_with_median_filter
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_FloorBumpFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_FloorBumpFx.xml
new file mode 100644
index 00000000..23fddf18
--- /dev/null
+++ b/stuff/profiles/layouts/fxs/STD_iwa_FloorBumpFx.xml
@@ -0,0 +1,39 @@
+
+
+ renderMode
+ fov
+ cameraAltitude
+ eyeLevel
+ drawLevel
+ waveHeight
+ souceMargin
+ displacement
+
+
+ sourcePrecision
+
+
+
+ textureOffsetAmount
+ textureOffsetSpread
+
+
+
+ lightAzimuth
+ lightElevation
+
+
+
+ depth
+ refractiveIndex
+
+
+
+ distanceLevel
+
+
+
+ differenceMode
+
+
+
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_FlowBlurFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_FlowBlurFx.xml
new file mode 100644
index 00000000..e2cb0bf6
--- /dev/null
+++ b/stuff/profiles/layouts/fxs/STD_iwa_FlowBlurFx.xml
@@ -0,0 +1,12 @@
+
+
+ length
+ filterType
+
+ linear
+
+ gamma
+
+ referenceMode
+
+
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_FlowPaintBrushFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_FlowPaintBrushFx.xml
new file mode 100644
index 00000000..08c347a3
--- /dev/null
+++ b/stuff/profiles/layouts/fxs/STD_iwa_FlowPaintBrushFx.xml
@@ -0,0 +1,32 @@
+
+
+
+ h_density
+ v_density
+ pos_randomness
+ pos_wobble
+
+ origin_pos
+ horizontal_pos
+ vertical_pos
+ curve_point
+ fill_gap_size
+
+ tip_width
+ width_randomness
+ sustain_width_to_skew
+ tip_length
+ length_randomness
+ angle_randomness
+ tip_alpha
+ tip_joints
+ bidirectional
+ anti_jaggy
+
+ reference_frame
+ reference_prevalence
+
+ random_seed
+ sort_by
+
+
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_GradientWarpFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_GradientWarpFx.xml
index 629917aa..19dadb7b 100644
--- a/stuff/profiles/layouts/fxs/STD_iwa_GradientWarpFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_iwa_GradientWarpFx.xml
@@ -3,5 +3,6 @@
h_maxlen
v_maxlen
scale
+ sampling_size
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_MotionBlurCompFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_MotionBlurCompFx.xml
index 419bb001..190b9759 100644
--- a/stuff/profiles/layouts/fxs/STD_iwa_MotionBlurCompFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_iwa_MotionBlurCompFx.xml
@@ -1,10 +1,10 @@
+
motionObjectType
-
motionObjectIndex
-
+
shutterStart
startValue
startCurve
@@ -13,6 +13,8 @@
endCurve
traceResolution
hardness
+ gamma
+ gammaAdjust
zanzoMode
premultiType
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_MotionFlowFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_MotionFlowFx.xml
new file mode 100644
index 00000000..a41426c5
--- /dev/null
+++ b/stuff/profiles/layouts/fxs/STD_iwa_MotionFlowFx.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ motionObjectType
+ motionObjectIndex
+
+ shutterLength
+ normalizeType
+
+ normalizeRange
+
+
+
+
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_TangentFlowFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_TangentFlowFx.xml
new file mode 100644
index 00000000..f9c0db23
--- /dev/null
+++ b/stuff/profiles/layouts/fxs/STD_iwa_TangentFlowFx.xml
@@ -0,0 +1,11 @@
+
+
+ iteration
+ kernelRadius
+ threshold
+ alignDirection
+
+ pivotAngle
+
+
+
diff --git a/stuff/profiles/layouts/fxs/STD_particlesFx.xml b/stuff/profiles/layouts/fxs/STD_particlesFx.xml
index 01972ba7..1ae1fe0f 100644
--- a/stuff/profiles/layouts/fxs/STD_particlesFx.xml
+++ b/stuff/profiles/layouts/fxs/STD_particlesFx.xml
@@ -56,9 +56,6 @@
mass
rot
rot_ctrl
-
- trail
- trail_step
lifetime
lifetime_ctrl
@@ -119,6 +116,14 @@
fade_out
trail_opacity
+
+ trail
+ trail_step
+
+
+ motion_blur
+ motion_blur_gamma_adjust
+
scale_step
scale_step_ctrl
diff --git a/stuff/profiles/layouts/fxs/fxs.lst b/stuff/profiles/layouts/fxs/fxs.lst
index cb844793..2de36847 100644
--- a/stuff/profiles/layouts/fxs/fxs.lst
+++ b/stuff/profiles/layouts/fxs/fxs.lst
@@ -23,6 +23,7 @@
STD_iwa_BokehFx
STD_iwa_BokehRefFx
STD_iwa_BokehAdvancedFx
+ STD_iwa_FlowBlurFx
STD_freeDistortFx
@@ -35,6 +36,7 @@
STD_warpFx
STD_inoWarphvFx
STD_iwa_BarrelDistortFx
+ STD_iwa_FloorBumpFx
STD_diamondGradientFx
@@ -155,6 +157,7 @@
STD_iwa_TiledParticlesFx
STD_iwa_TimeCodeFx
STD_iwa_TextFx
+ STD_iwa_FlowPaintBrushFx
STD_colorEmbossFx
@@ -163,7 +166,9 @@
STD_mosaicFx
STD_inoMotionWindFx
STD_posterizeFx
- STD_solarizeFx
+ STD_solarizeFx
+ STD_iwa_TangentFlowFx
+ STD_iwa_MotionFlowFx
STD_artContourFx
diff --git a/thirdparty/tinyexr/tinyexr.h b/thirdparty/tinyexr/tinyexr.h
new file mode 100644
index 00000000..969f07ad
--- /dev/null
+++ b/thirdparty/tinyexr/tinyexr.h
@@ -0,0 +1,8530 @@
+#ifndef TINYEXR_H_
+#define TINYEXR_H_
+/*
+Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors.
+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 the Syoyo Fujita 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 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.
+*/
+
+// TinyEXR contains some OpenEXR code, which is licensed under ------------
+
+///////////////////////////////////////////////////////////////////////////
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////
+
+// End of OpenEXR license -------------------------------------------------
+
+
+//
+//
+// Do this:
+// #define TINYEXR_IMPLEMENTATION
+// before you include this file in *one* C or C++ file to create the
+// implementation.
+//
+// // i.e. it should look like this:
+// #include ...
+// #include ...
+// #include ...
+// #define TINYEXR_IMPLEMENTATION
+// #include "tinyexr.h"
+//
+//
+
+#include // for size_t
+#include // guess stdint.h is available(C99)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
+ defined(__i386) || defined(__i486__) || defined(__i486) || \
+ defined(i386) || defined(__ia64__) || defined(__x86_64__)
+#define TINYEXR_X86_OR_X64_CPU 1
+#else
+#define TINYEXR_X86_OR_X64_CPU 0
+#endif
+
+#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || TINYEXR_X86_OR_X64_CPU
+#define TINYEXR_LITTLE_ENDIAN 1
+#else
+#define TINYEXR_LITTLE_ENDIAN 0
+#endif
+
+// Use miniz or not to decode ZIP format pixel. Linking with zlib
+// required if this flas is 0.
+#ifndef TINYEXR_USE_MINIZ
+#define TINYEXR_USE_MINIZ (1)
+#endif
+
+// Disable PIZ comporession when applying cpplint.
+#ifndef TINYEXR_USE_PIZ
+#define TINYEXR_USE_PIZ (1)
+#endif
+
+#ifndef TINYEXR_USE_ZFP
+#define TINYEXR_USE_ZFP (0) // TinyEXR extension.
+// http://computation.llnl.gov/projects/floating-point-compression
+#endif
+
+#ifndef TINYEXR_USE_THREAD
+#define TINYEXR_USE_THREAD (0) // No threaded loading.
+// http://computation.llnl.gov/projects/floating-point-compression
+#endif
+
+#ifndef TINYEXR_USE_OPENMP
+#ifdef _OPENMP
+#define TINYEXR_USE_OPENMP (1)
+#else
+#define TINYEXR_USE_OPENMP (0)
+#endif
+#endif
+
+#define TINYEXR_SUCCESS (0)
+#define TINYEXR_ERROR_INVALID_MAGIC_NUMBER (-1)
+#define TINYEXR_ERROR_INVALID_EXR_VERSION (-2)
+#define TINYEXR_ERROR_INVALID_ARGUMENT (-3)
+#define TINYEXR_ERROR_INVALID_DATA (-4)
+#define TINYEXR_ERROR_INVALID_FILE (-5)
+#define TINYEXR_ERROR_INVALID_PARAMETER (-6)
+#define TINYEXR_ERROR_CANT_OPEN_FILE (-7)
+#define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-8)
+#define TINYEXR_ERROR_INVALID_HEADER (-9)
+#define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-10)
+#define TINYEXR_ERROR_CANT_WRITE_FILE (-11)
+#define TINYEXR_ERROR_SERIALZATION_FAILED (-12)
+#define TINYEXR_ERROR_LAYER_NOT_FOUND (-13)
+
+// @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf }
+
+// pixel type: possible values are: UINT = 0 HALF = 1 FLOAT = 2
+#define TINYEXR_PIXELTYPE_UINT (0)
+#define TINYEXR_PIXELTYPE_HALF (1)
+#define TINYEXR_PIXELTYPE_FLOAT (2)
+
+#define TINYEXR_MAX_HEADER_ATTRIBUTES (1024)
+#define TINYEXR_MAX_CUSTOM_ATTRIBUTES (128)
+
+#define TINYEXR_COMPRESSIONTYPE_NONE (0)
+#define TINYEXR_COMPRESSIONTYPE_RLE (1)
+#define TINYEXR_COMPRESSIONTYPE_ZIPS (2)
+#define TINYEXR_COMPRESSIONTYPE_ZIP (3)
+#define TINYEXR_COMPRESSIONTYPE_PIZ (4)
+#define TINYEXR_COMPRESSIONTYPE_ZFP (128) // TinyEXR extension
+
+#define TINYEXR_ZFP_COMPRESSIONTYPE_RATE (0)
+#define TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION (1)
+#define TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY (2)
+
+#define TINYEXR_TILE_ONE_LEVEL (0)
+#define TINYEXR_TILE_MIPMAP_LEVELS (1)
+#define TINYEXR_TILE_RIPMAP_LEVELS (2)
+
+#define TINYEXR_TILE_ROUND_DOWN (0)
+#define TINYEXR_TILE_ROUND_UP (1)
+
+typedef struct _EXRVersion {
+ int version; // this must be 2
+ // tile format image;
+ // not zero for only a single-part "normal" tiled file (according to spec.)
+ int tiled;
+ int long_name; // long name attribute
+ // deep image(EXR 2.0);
+ // for a multi-part file, indicates that at least one part is of type deep* (according to spec.)
+ int non_image;
+ int multipart; // multi-part(EXR 2.0)
+} EXRVersion;
+
+typedef struct _EXRAttribute {
+ char name[256]; // name and type are up to 255 chars long.
+ char type[256];
+ unsigned char *value; // uint8_t*
+ int size;
+ int pad0;
+} EXRAttribute;
+
+typedef struct _EXRChannelInfo {
+ char name[256]; // less than 255 bytes long
+ int pixel_type;
+ int x_sampling;
+ int y_sampling;
+ unsigned char p_linear;
+ unsigned char pad[3];
+} EXRChannelInfo;
+
+typedef struct _EXRTile {
+ int offset_x;
+ int offset_y;
+ int level_x;
+ int level_y;
+
+ int width; // actual width in a tile.
+ int height; // actual height int a tile.
+
+ unsigned char **images; // image[channels][pixels]
+} EXRTile;
+
+typedef struct _EXRBox2i {
+ int min_x;
+ int min_y;
+ int max_x;
+ int max_y;
+} EXRBox2i;
+
+typedef struct _EXRHeader {
+ float pixel_aspect_ratio;
+ int line_order;
+ EXRBox2i data_window;
+ EXRBox2i display_window;
+ float screen_window_center[2];
+ float screen_window_width;
+
+ int chunk_count;
+
+ // Properties for tiled format(`tiledesc`).
+ int tiled;
+ int tile_size_x;
+ int tile_size_y;
+ int tile_level_mode;
+ int tile_rounding_mode;
+
+ int long_name;
+ // for a single-part file, agree with the version field bit 11
+ // for a multi-part file, it is consistent with the type of part
+ int non_image;
+ int multipart;
+ unsigned int header_len;
+
+ // Custom attributes(exludes required attributes(e.g. `channels`,
+ // `compression`, etc)
+ int num_custom_attributes;
+ EXRAttribute *custom_attributes; // array of EXRAttribute. size =
+ // `num_custom_attributes`.
+
+ EXRChannelInfo *channels; // [num_channels]
+
+ int *pixel_types; // Loaded pixel type(TINYEXR_PIXELTYPE_*) of `images` for
+ // each channel. This is overwritten with `requested_pixel_types` when
+ // loading.
+ int num_channels;
+
+ int compression_type; // compression type(TINYEXR_COMPRESSIONTYPE_*)
+ int *requested_pixel_types; // Filled initially by
+ // ParseEXRHeaderFrom(Meomory|File), then users
+ // can edit it(only valid for HALF pixel type
+ // channel)
+ // name attribute required for multipart files;
+ // must be unique and non empty (according to spec.);
+ // use EXRSetNameAttr for setting value;
+ // max 255 character allowed - excluding terminating zero
+ char name[256];
+} EXRHeader;
+
+typedef struct _EXRMultiPartHeader {
+ int num_headers;
+ EXRHeader *headers;
+
+} EXRMultiPartHeader;
+
+typedef struct _EXRImage {
+ EXRTile *tiles; // Tiled pixel data. The application must reconstruct image
+ // from tiles manually. NULL if scanline format.
+ struct _EXRImage* next_level; // NULL if scanline format or image is the last level.
+ int level_x; // x level index
+ int level_y; // y level index
+
+ unsigned char **images; // image[channels][pixels]. NULL if tiled format.
+
+ int width;
+ int height;
+ int num_channels;
+
+ // Properties for tile format.
+ int num_tiles;
+
+} EXRImage;
+
+typedef struct _EXRMultiPartImage {
+ int num_images;
+ EXRImage *images;
+
+} EXRMultiPartImage;
+
+typedef struct _DeepImage {
+ const char **channel_names;
+ float ***image; // image[channels][scanlines][samples]
+ int **offset_table; // offset_table[scanline][offsets]
+ int num_channels;
+ int width;
+ int height;
+ int pad0;
+} DeepImage;
+
+// @deprecated { For backward compatibility. Not recommended to use. }
+// Loads single-frame OpenEXR image. Assume EXR image contains A(single channel
+// alpha) or RGB(A) channels.
+// Application must free image data as returned by `out_rgba`
+// Result image format is: float x RGBA x width x hight
+// Returns negative value and may set error string in `err` when there's an
+// error
+extern int LoadEXR(float **out_rgba, int *width, int *height,
+ const char *filename, const char **err);
+
+// Loads single-frame OpenEXR image by specifying layer name. Assume EXR image
+// contains A(single channel alpha) or RGB(A) channels. Application must free
+// image data as returned by `out_rgba` Result image format is: float x RGBA x
+// width x hight Returns negative value and may set error string in `err` when
+// there's an error When the specified layer name is not found in the EXR file,
+// the function will return `TINYEXR_ERROR_LAYER_NOT_FOUND`.
+extern int LoadEXRWithLayer(float **out_rgba, int *width, int *height,
+ const char *filename, const char *layer_name,
+ const char **err);
+
+//
+// Get layer infos from EXR file.
+//
+// @param[out] layer_names List of layer names. Application must free memory
+// after using this.
+// @param[out] num_layers The number of layers
+// @param[out] err Error string(will be filled when the function returns error
+// code). Free it using FreeEXRErrorMessage after using this value.
+//
+// @return TINYEXR_SUCCEES upon success.
+//
+extern int EXRLayers(const char *filename, const char **layer_names[],
+ int *num_layers, const char **err);
+
+// @deprecated { to be removed. }
+// Simple wrapper API for ParseEXRHeaderFromFile.
+// checking given file is a EXR file(by just look up header)
+// @return TINYEXR_SUCCEES for EXR image, TINYEXR_ERROR_INVALID_HEADER for
+// others
+extern int IsEXR(const char *filename);
+
+// @deprecated { to be removed. }
+// Saves single-frame OpenEXR image. Assume EXR image contains RGB(A) channels.
+// components must be 1(Grayscale), 3(RGB) or 4(RGBA).
+// Input image format is: `float x width x height`, or `float x RGB(A) x width x
+// hight`
+// Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero
+// value.
+// Save image as fp32(FLOAT) format when `save_as_fp16` is 0.
+// Use ZIP compression by default.
+// Returns negative value and may set error string in `err` when there's an
+// error
+extern int SaveEXR(const float *data, const int width, const int height,
+ const int components, const int save_as_fp16,
+ const char *filename, const char **err);
+
+// Returns the number of resolution levels of the image (including the base)
+extern int EXRNumLevels(const EXRImage* exr_image);
+
+// Initialize EXRHeader struct
+extern void InitEXRHeader(EXRHeader *exr_header);
+
+// Set name attribute of EXRHeader struct (it makes a copy)
+extern void EXRSetNameAttr(EXRHeader *exr_header, const char* name);
+
+// Initialize EXRImage struct
+extern void InitEXRImage(EXRImage *exr_image);
+
+// Frees internal data of EXRHeader struct
+extern int FreeEXRHeader(EXRHeader *exr_header);
+
+// Frees internal data of EXRImage struct
+extern int FreeEXRImage(EXRImage *exr_image);
+
+// Frees error message
+extern void FreeEXRErrorMessage(const char *msg);
+
+// Parse EXR version header of a file.
+extern int ParseEXRVersionFromFile(EXRVersion *version, const char *filename);
+
+// Parse EXR version header from memory-mapped EXR data.
+extern int ParseEXRVersionFromMemory(EXRVersion *version,
+ const unsigned char *memory, size_t size);
+
+// Parse single-part OpenEXR header from a file and initialize `EXRHeader`.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version,
+ const char *filename, const char **err);
+
+// Parse single-part OpenEXR header from a memory and initialize `EXRHeader`.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int ParseEXRHeaderFromMemory(EXRHeader *header,
+ const EXRVersion *version,
+ const unsigned char *memory, size_t size,
+ const char **err);
+
+// Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*`
+// array.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers,
+ int *num_headers,
+ const EXRVersion *version,
+ const char *filename,
+ const char **err);
+
+// Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*`
+// array
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers,
+ int *num_headers,
+ const EXRVersion *version,
+ const unsigned char *memory,
+ size_t size, const char **err);
+
+// Loads single-part OpenEXR image from a file.
+// Application must setup `ParseEXRHeaderFromFile` before calling this function.
+// Application can free EXRImage using `FreeEXRImage`
+// Returns negative value and may set error string in `err` when there's an
+// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header,
+ const char *filename, const char **err);
+
+// Loads single-part OpenEXR image from a memory.
+// Application must setup `EXRHeader` with
+// `ParseEXRHeaderFromMemory` before calling this function.
+// Application can free EXRImage using `FreeEXRImage`
+// Returns negative value and may set error string in `err` when there's an
+// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header,
+ const unsigned char *memory,
+ const size_t size, const char **err);
+
+// Loads multi-part OpenEXR image from a file.
+// Application must setup `ParseEXRMultipartHeaderFromFile` before calling this
+// function.
+// Application can free EXRImage using `FreeEXRImage`
+// Returns negative value and may set error string in `err` when there's an
+// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int LoadEXRMultipartImageFromFile(EXRImage *images,
+ const EXRHeader **headers,
+ unsigned int num_parts,
+ const char *filename,
+ const char **err);
+
+// Loads multi-part OpenEXR image from a memory.
+// Application must setup `EXRHeader*` array with
+// `ParseEXRMultipartHeaderFromMemory` before calling this function.
+// Application can free EXRImage using `FreeEXRImage`
+// Returns negative value and may set error string in `err` when there's an
+// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int LoadEXRMultipartImageFromMemory(EXRImage *images,
+ const EXRHeader **headers,
+ unsigned int num_parts,
+ const unsigned char *memory,
+ const size_t size, const char **err);
+
+// Saves multi-channel, single-frame OpenEXR image to a file.
+// Returns negative value and may set error string in `err` when there's an
+// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int SaveEXRImageToFile(const EXRImage *image,
+ const EXRHeader *exr_header, const char *filename,
+ const char **err);
+
+// Saves multi-channel, single-frame OpenEXR image to a memory.
+// Image is compressed using EXRImage.compression value.
+// Return the number of bytes if success.
+// Return zero and will set error string in `err` when there's an
+// error.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern size_t SaveEXRImageToMemory(const EXRImage *image,
+ const EXRHeader *exr_header,
+ unsigned char **memory, const char **err);
+
+// Saves multi-channel, multi-frame OpenEXR image to a memory.
+// Image is compressed using EXRImage.compression value.
+// File global attributes (eg. display_window) must be set in the first header.
+// Returns negative value and may set error string in `err` when there's an
+// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int SaveEXRMultipartImageToFile(const EXRImage *images,
+ const EXRHeader **exr_headers,
+ unsigned int num_parts,
+ const char *filename, const char **err);
+
+// Saves multi-channel, multi-frame OpenEXR image to a memory.
+// Image is compressed using EXRImage.compression value.
+// File global attributes (eg. display_window) must be set in the first header.
+// Return the number of bytes if success.
+// Return zero and will set error string in `err` when there's an
+// error.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern size_t SaveEXRMultipartImageToMemory(const EXRImage *images,
+ const EXRHeader **exr_headers,
+ unsigned int num_parts,
+ unsigned char **memory, const char **err);
+// Loads single-frame OpenEXR deep image.
+// Application must free memory of variables in DeepImage(image, offset_table)
+// Returns negative value and may set error string in `err` when there's an
+// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
+ const char **err);
+
+// NOT YET IMPLEMENTED:
+// Saves single-frame OpenEXR deep image.
+// Returns negative value and may set error string in `err` when there's an
+// error
+// extern int SaveDeepEXR(const DeepImage *in_image, const char *filename,
+// const char **err);
+
+// NOT YET IMPLEMENTED:
+// Loads multi-part OpenEXR deep image.
+// Application must free memory of variables in DeepImage(image, offset_table)
+// extern int LoadMultiPartDeepEXR(DeepImage **out_image, int num_parts, const
+// char *filename,
+// const char **err);
+
+// For emscripten.
+// Loads single-frame OpenEXR image from memory. Assume EXR image contains
+// RGB(A) channels.
+// Returns negative value and may set error string in `err` when there's an
+// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
+extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
+ const unsigned char *memory, size_t size,
+ const char **err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // TINYEXR_H_
+
+#ifdef TINYEXR_IMPLEMENTATION
+#ifndef TINYEXR_IMPLEMENTATION_DEFINED
+#define TINYEXR_IMPLEMENTATION_DEFINED
+
+#ifdef _WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#include // for UTF-8
+
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+// #include // debug
+
+#include
+#include
+#include
+#include
+
+// https://stackoverflow.com/questions/5047971/how-do-i-check-for-c11-support
+#if __cplusplus > 199711L || (defined(_MSC_VER) && _MSC_VER >= 1900)
+#define TINYEXR_HAS_CXX11 (1)
+// C++11
+#include
+
+#if TINYEXR_USE_THREAD
+#include
+#include
+#endif
+
+#endif // __cplusplus > 199711L
+
+#if TINYEXR_USE_OPENMP
+#include
+#endif
+
+#if TINYEXR_USE_MINIZ
+#include
+#else
+// Issue #46. Please include your own zlib-compatible API header before
+// including `tinyexr.h`
+//#include "zlib.h"
+#endif
+
+#if TINYEXR_USE_ZFP
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+#endif
+
+#include "zfp.h"
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+
+namespace tinyexr {
+
+#if __cplusplus > 199711L
+// C++11
+typedef uint64_t tinyexr_uint64;
+typedef int64_t tinyexr_int64;
+#else
+// Although `long long` is not a standard type pre C++11, assume it is defined
+// as a compiler's extension.
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+#endif
+typedef unsigned long long tinyexr_uint64;
+typedef long long tinyexr_int64;
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+#endif
+
+// static bool IsBigEndian(void) {
+// union {
+// unsigned int i;
+// char c[4];
+// } bint = {0x01020304};
+//
+// return bint.c[0] == 1;
+//}
+
+static void SetErrorMessage(const std::string &msg, const char **err) {
+ if (err) {
+#ifdef _WIN32
+ (*err) = _strdup(msg.c_str());
+#else
+ (*err) = strdup(msg.c_str());
+#endif
+ }
+}
+
+static const int kEXRVersionSize = 8;
+
+static void cpy2(unsigned short *dst_val, const unsigned short *src_val) {
+ unsigned char *dst = reinterpret_cast(dst_val);
+ const unsigned char *src = reinterpret_cast(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+}
+
+static void swap2(unsigned short *val) {
+#ifdef TINYEXR_LITTLE_ENDIAN
+ (void)val;
+#else
+ unsigned short tmp = *val;
+ unsigned char *dst = reinterpret_cast(val);
+ unsigned char *src = reinterpret_cast(&tmp);
+
+ dst[0] = src[1];
+ dst[1] = src[0];
+#endif
+}
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+static void cpy4(int *dst_val, const int *src_val) {
+ unsigned char *dst = reinterpret_cast(dst_val);
+ const unsigned char *src = reinterpret_cast(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+}
+
+static void cpy4(unsigned int *dst_val, const unsigned int *src_val) {
+ unsigned char *dst = reinterpret_cast(dst_val);
+ const unsigned char *src = reinterpret_cast(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+}
+
+static void cpy4(float *dst_val, const float *src_val) {
+ unsigned char *dst = reinterpret_cast(dst_val);
+ const unsigned char *src = reinterpret_cast(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+}
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+static void swap4(unsigned int *val) {
+#ifdef TINYEXR_LITTLE_ENDIAN
+ (void)val;
+#else
+ unsigned int tmp = *val;
+ unsigned char *dst = reinterpret_cast(val);
+ unsigned char *src = reinterpret_cast(&tmp);
+
+ dst[0] = src[3];
+ dst[1] = src[2];
+ dst[2] = src[1];
+ dst[3] = src[0];
+#endif
+}
+
+static void swap4(int *val) {
+#ifdef TINYEXR_LITTLE_ENDIAN
+ (void)val;
+#else
+ int tmp = *val;
+ unsigned char *dst = reinterpret_cast(val);
+ unsigned char *src = reinterpret_cast(&tmp);
+
+ dst[0] = src[3];
+ dst[1] = src[2];
+ dst[2] = src[1];
+ dst[3] = src[0];
+#endif
+}
+
+static void swap4(float *val) {
+#ifdef TINYEXR_LITTLE_ENDIAN
+ (void)val;
+#else
+ float tmp = *val;
+ unsigned char *dst = reinterpret_cast(val);
+ unsigned char *src = reinterpret_cast(&tmp);
+
+ dst[0] = src[3];
+ dst[1] = src[2];
+ dst[2] = src[1];
+ dst[3] = src[0];
+#endif
+}
+
+#if 0
+static void cpy8(tinyexr::tinyexr_uint64 *dst_val, const tinyexr::tinyexr_uint64 *src_val) {
+ unsigned char *dst = reinterpret_cast(dst_val);
+ const unsigned char *src = reinterpret_cast(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[5] = src[5];
+ dst[6] = src[6];
+ dst[7] = src[7];
+}
+#endif
+
+static void swap8(tinyexr::tinyexr_uint64 *val) {
+#ifdef TINYEXR_LITTLE_ENDIAN
+ (void)val;
+#else
+ tinyexr::tinyexr_uint64 tmp = (*val);
+ unsigned char *dst = reinterpret_cast(val);
+ unsigned char *src = reinterpret_cast(&tmp);
+
+ dst[0] = src[7];
+ dst[1] = src[6];
+ dst[2] = src[5];
+ dst[3] = src[4];
+ dst[4] = src[3];
+ dst[5] = src[2];
+ dst[6] = src[1];
+ dst[7] = src[0];
+#endif
+}
+
+// https://gist.github.com/rygorous/2156668
+union FP32 {
+ unsigned int u;
+ float f;
+ struct {
+#if TINYEXR_LITTLE_ENDIAN
+ unsigned int Mantissa : 23;
+ unsigned int Exponent : 8;
+ unsigned int Sign : 1;
+#else
+ unsigned int Sign : 1;
+ unsigned int Exponent : 8;
+ unsigned int Mantissa : 23;
+#endif
+ } s;
+};
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+union FP16 {
+ unsigned short u;
+ struct {
+#if TINYEXR_LITTLE_ENDIAN
+ unsigned int Mantissa : 10;
+ unsigned int Exponent : 5;
+ unsigned int Sign : 1;
+#else
+ unsigned int Sign : 1;
+ unsigned int Exponent : 5;
+ unsigned int Mantissa : 10;
+#endif
+ } s;
+};
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+static FP32 half_to_float(FP16 h) {
+ static const FP32 magic = {113 << 23};
+ static const unsigned int shifted_exp = 0x7c00
+ << 13; // exponent mask after shift
+ FP32 o;
+
+ o.u = (h.u & 0x7fffU) << 13U; // exponent/mantissa bits
+ unsigned int exp_ = shifted_exp & o.u; // just the exponent
+ o.u += (127 - 15) << 23; // exponent adjust
+
+ // handle exponent special cases
+ if (exp_ == shifted_exp) // Inf/NaN?
+ o.u += (128 - 16) << 23; // extra exp adjust
+ else if (exp_ == 0) // Zero/Denormal?
+ {
+ o.u += 1 << 23; // extra exp adjust
+ o.f -= magic.f; // renormalize
+ }
+
+ o.u |= (h.u & 0x8000U) << 16U; // sign bit
+ return o;
+}
+
+static FP16 float_to_half_full(FP32 f) {
+ FP16 o = {0};
+
+ // Based on ISPC reference code (with minor modifications)
+ if (f.s.Exponent == 0) // Signed zero/denormal (which will underflow)
+ o.s.Exponent = 0;
+ else if (f.s.Exponent == 255) // Inf or NaN (all exponent bits set)
+ {
+ o.s.Exponent = 31;
+ o.s.Mantissa = f.s.Mantissa ? 0x200 : 0; // NaN->qNaN and Inf->Inf
+ } else // Normalized number
+ {
+ // Exponent unbias the single, then bias the halfp
+ int newexp = f.s.Exponent - 127 + 15;
+ if (newexp >= 31) // Overflow, return signed infinity
+ o.s.Exponent = 31;
+ else if (newexp <= 0) // Underflow
+ {
+ if ((14 - newexp) <= 24) // Mantissa might be non-zero
+ {
+ unsigned int mant = f.s.Mantissa | 0x800000; // Hidden 1 bit
+ o.s.Mantissa = mant >> (14 - newexp);
+ if ((mant >> (13 - newexp)) & 1) // Check for rounding
+ o.u++; // Round, might overflow into exp bit, but this is OK
+ }
+ } else {
+ o.s.Exponent = static_cast(newexp);
+ o.s.Mantissa = f.s.Mantissa >> 13;
+ if (f.s.Mantissa & 0x1000) // Check for rounding
+ o.u++; // Round, might overflow to inf, this is OK
+ }
+ }
+
+ o.s.Sign = f.s.Sign;
+ return o;
+}
+
+// NOTE: From OpenEXR code
+// #define IMF_INCREASING_Y 0
+// #define IMF_DECREASING_Y 1
+// #define IMF_RAMDOM_Y 2
+//
+// #define IMF_NO_COMPRESSION 0
+// #define IMF_RLE_COMPRESSION 1
+// #define IMF_ZIPS_COMPRESSION 2
+// #define IMF_ZIP_COMPRESSION 3
+// #define IMF_PIZ_COMPRESSION 4
+// #define IMF_PXR24_COMPRESSION 5
+// #define IMF_B44_COMPRESSION 6
+// #define IMF_B44A_COMPRESSION 7
+
+#ifdef __clang__
+#pragma clang diagnostic push
+
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+#endif
+
+#endif
+
+static const char *ReadString(std::string *s, const char *ptr, size_t len) {
+ // Read untile NULL(\0).
+ const char *p = ptr;
+ const char *q = ptr;
+ while ((size_t(q - ptr) < len) && (*q) != 0) {
+ q++;
+ }
+
+ if (size_t(q - ptr) >= len) {
+ (*s).clear();
+ return NULL;
+ }
+
+ (*s) = std::string(p, q);
+
+ return q + 1; // skip '\0'
+}
+
+static bool ReadAttribute(std::string *name, std::string *type,
+ std::vector *data, size_t *marker_size,
+ const char *marker, size_t size) {
+ size_t name_len = strnlen(marker, size);
+ if (name_len == size) {
+ // String does not have a terminating character.
+ return false;
+ }
+ *name = std::string(marker, name_len);
+
+ marker += name_len + 1;
+ size -= name_len + 1;
+
+ size_t type_len = strnlen(marker, size);
+ if (type_len == size) {
+ return false;
+ }
+ *type = std::string(marker, type_len);
+
+ marker += type_len + 1;
+ size -= type_len + 1;
+
+ if (size < sizeof(uint32_t)) {
+ return false;
+ }
+
+ uint32_t data_len;
+ memcpy(&data_len, marker, sizeof(uint32_t));
+ tinyexr::swap4(reinterpret_cast(&data_len));
+
+ if (data_len == 0) {
+ if ((*type).compare("string") == 0) {
+ // Accept empty string attribute.
+
+ marker += sizeof(uint32_t);
+ size -= sizeof(uint32_t);
+
+ *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t);
+
+ data->resize(1);
+ (*data)[0] = '\0';
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ marker += sizeof(uint32_t);
+ size -= sizeof(uint32_t);
+
+ if (size < data_len) {
+ return false;
+ }
+
+ data->resize(static_cast(data_len));
+ memcpy(&data->at(0), marker, static_cast(data_len));
+
+ *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t) + data_len;
+ return true;
+}
+
+static void WriteAttributeToMemory(std::vector *out,
+ const char *name, const char *type,
+ const unsigned char *data, int len) {
+ out->insert(out->end(), name, name + strlen(name) + 1);
+ out->insert(out->end(), type, type + strlen(type) + 1);
+
+ int outLen = len;
+ tinyexr::swap4(&outLen);
+ out->insert(out->end(), reinterpret_cast(&outLen),
+ reinterpret_cast(&outLen) + sizeof(int));
+ out->insert(out->end(), data, data + len);
+}
+
+typedef struct {
+ std::string name; // less than 255 bytes long
+ int pixel_type;
+ int requested_pixel_type;
+ int x_sampling;
+ int y_sampling;
+ unsigned char p_linear;
+ unsigned char pad[3];
+} ChannelInfo;
+
+typedef struct {
+ int min_x;
+ int min_y;
+ int max_x;
+ int max_y;
+} Box2iInfo;
+
+struct HeaderInfo {
+ std::vector channels;
+ std::vector attributes;
+
+ Box2iInfo data_window;
+ int line_order;
+ Box2iInfo display_window;
+ float screen_window_center[2];
+ float screen_window_width;
+ float pixel_aspect_ratio;
+
+ int chunk_count;
+
+ // Tiled format
+ int tiled; // Non-zero if the part is tiled.
+ int tile_size_x;
+ int tile_size_y;
+ int tile_level_mode;
+ int tile_rounding_mode;
+
+ unsigned int header_len;
+
+ int compression_type;
+
+ // required for multi-part or non-image files
+ std::string name;
+ // required for multi-part or non-image files
+ std::string type;
+
+ void clear() {
+ channels.clear();
+ attributes.clear();
+
+ data_window.min_x = 0;
+ data_window.min_y = 0;
+ data_window.max_x = 0;
+ data_window.max_y = 0;
+ line_order = 0;
+ display_window.min_x = 0;
+ display_window.min_y = 0;
+ display_window.max_x = 0;
+ display_window.max_y = 0;
+ screen_window_center[0] = 0.0f;
+ screen_window_center[1] = 0.0f;
+ screen_window_width = 0.0f;
+ pixel_aspect_ratio = 0.0f;
+
+ chunk_count = 0;
+
+ // Tiled format
+ tiled = 0;
+ tile_size_x = 0;
+ tile_size_y = 0;
+ tile_level_mode = 0;
+ tile_rounding_mode = 0;
+
+ header_len = 0;
+ compression_type = 0;
+
+ name.clear();
+ type.clear();
+ }
+};
+
+static bool ReadChannelInfo(std::vector &channels,
+ const std::vector &data) {
+ const char *p = reinterpret_cast(&data.at(0));
+
+ for (;;) {
+ if ((*p) == 0) {
+ break;
+ }
+ ChannelInfo info;
+
+ tinyexr_int64 data_len = static_cast(data.size()) -
+ (p - reinterpret_cast(data.data()));
+ if (data_len < 0) {
+ return false;
+ }
+
+ p = ReadString(&info.name, p, size_t(data_len));
+ if ((p == NULL) && (info.name.empty())) {
+ // Buffer overrun. Issue #51.
+ return false;
+ }
+
+ const unsigned char *data_end =
+ reinterpret_cast(p) + 16;
+ if (data_end >= (data.data() + data.size())) {
+ return false;
+ }
+
+ memcpy(&info.pixel_type, p, sizeof(int));
+ p += 4;
+ info.p_linear = static_cast(p[0]); // uchar
+ p += 1 + 3; // reserved: uchar[3]
+ memcpy(&info.x_sampling, p, sizeof(int)); // int
+ p += 4;
+ memcpy(&info.y_sampling, p, sizeof(int)); // int
+ p += 4;
+
+ tinyexr::swap4(&info.pixel_type);
+ tinyexr::swap4(&info.x_sampling);
+ tinyexr::swap4(&info.y_sampling);
+
+ channels.push_back(info);
+ }
+
+ return true;
+}
+
+static void WriteChannelInfo(std::vector &data,
+ const std::vector &channels) {
+ size_t sz = 0;
+
+ // Calculate total size.
+ for (size_t c = 0; c < channels.size(); c++) {
+ sz += channels[c].name.length() + 1; // +1 for \0
+ sz += 16; // 4 * int
+ }
+ data.resize(sz + 1);
+
+ unsigned char *p = &data.at(0);
+
+ for (size_t c = 0; c < channels.size(); c++) {
+ memcpy(p, channels[c].name.c_str(), channels[c].name.length());
+ p += channels[c].name.length();
+ (*p) = '\0';
+ p++;
+
+ int pixel_type = channels[c].requested_pixel_type;
+ int x_sampling = channels[c].x_sampling;
+ int y_sampling = channels[c].y_sampling;
+ tinyexr::swap4(&pixel_type);
+ tinyexr::swap4(&x_sampling);
+ tinyexr::swap4(&y_sampling);
+
+ memcpy(p, &pixel_type, sizeof(int));
+ p += sizeof(int);
+
+ (*p) = channels[c].p_linear;
+ p += 4;
+
+ memcpy(p, &x_sampling, sizeof(int));
+ p += sizeof(int);
+
+ memcpy(p, &y_sampling, sizeof(int));
+ p += sizeof(int);
+ }
+
+ (*p) = '\0';
+}
+
+static void CompressZip(unsigned char *dst,
+ tinyexr::tinyexr_uint64 &compressedSize,
+ const unsigned char *src, unsigned long src_size) {
+ std::vector tmpBuf(src_size);
+
+ //
+ // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
+ // ImfZipCompressor.cpp
+ //
+
+ //
+ // Reorder the pixel data.
+ //
+
+ const char *srcPtr = reinterpret_cast(src);
+
+ {
+ char *t1 = reinterpret_cast(&tmpBuf.at(0));
+ char *t2 = reinterpret_cast(&tmpBuf.at(0)) + (src_size + 1) / 2;
+ const char *stop = srcPtr + src_size;
+
+ for (;;) {
+ if (srcPtr < stop)
+ *(t1++) = *(srcPtr++);
+ else
+ break;
+
+ if (srcPtr < stop)
+ *(t2++) = *(srcPtr++);
+ else
+ break;
+ }
+ }
+
+ //
+ // Predictor.
+ //
+
+ {
+ unsigned char *t = &tmpBuf.at(0) + 1;
+ unsigned char *stop = &tmpBuf.at(0) + src_size;
+ int p = t[-1];
+
+ while (t < stop) {
+ int d = int(t[0]) - p + (128 + 256);
+ p = t[0];
+ t[0] = static_cast(d);
+ ++t;
+ }
+ }
+
+#if TINYEXR_USE_MINIZ
+ //
+ // Compress the data using miniz
+ //
+
+ mz_ulong outSize = mz_compressBound(src_size);
+ int ret = mz_compress(
+ dst, &outSize, static_cast(&tmpBuf.at(0)),
+ src_size);
+ assert(ret == MZ_OK);
+ (void)ret;
+
+ compressedSize = outSize;
+#else
+ uLong outSize = compressBound(static_cast(src_size));
+ int ret = compress(dst, &outSize, static_cast(&tmpBuf.at(0)),
+ src_size);
+ assert(ret == Z_OK);
+
+ compressedSize = outSize;
+#endif
+
+ // Use uncompressed data when compressed data is larger than uncompressed.
+ // (Issue 40)
+ if (compressedSize >= src_size) {
+ compressedSize = src_size;
+ memcpy(dst, src, src_size);
+ }
+}
+
+static bool DecompressZip(unsigned char *dst,
+ unsigned long *uncompressed_size /* inout */,
+ const unsigned char *src, unsigned long src_size) {
+ if ((*uncompressed_size) == src_size) {
+ // Data is not compressed(Issue 40).
+ memcpy(dst, src, src_size);
+ return true;
+ }
+ std::vector tmpBuf(*uncompressed_size);
+
+#if TINYEXR_USE_MINIZ
+ int ret =
+ mz_uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
+ if (MZ_OK != ret) {
+ return false;
+ }
+#else
+ int ret = uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
+ if (Z_OK != ret) {
+ return false;
+ }
+#endif
+
+ //
+ // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
+ // ImfZipCompressor.cpp
+ //
+
+ // Predictor.
+ {
+ unsigned char *t = &tmpBuf.at(0) + 1;
+ unsigned char *stop = &tmpBuf.at(0) + (*uncompressed_size);
+
+ while (t < stop) {
+ int d = int(t[-1]) + int(t[0]) - 128;
+ t[0] = static_cast(d);
+ ++t;
+ }
+ }
+
+ // Reorder the pixel data.
+ {
+ const char *t1 = reinterpret_cast(&tmpBuf.at(0));
+ const char *t2 = reinterpret_cast(&tmpBuf.at(0)) +
+ (*uncompressed_size + 1) / 2;
+ char *s = reinterpret_cast(dst);
+ char *stop = s + (*uncompressed_size);
+
+ for (;;) {
+ if (s < stop)
+ *(s++) = *(t1++);
+ else
+ break;
+
+ if (s < stop)
+ *(s++) = *(t2++);
+ else
+ break;
+ }
+ }
+
+ return true;
+}
+
+// RLE code from OpenEXR --------------------------------------
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#if __has_warning("-Wextra-semi-stmt")
+#pragma clang diagnostic ignored "-Wextra-semi-stmt"
+#endif
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4204) // nonstandard extension used : non-constant
+ // aggregate initializer (also supported by GNU
+ // C and C99, so no big deal)
+#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to
+ // 'int', possible loss of data
+#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to
+ // 'int', possible loss of data
+#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is
+ // deprecated. Instead, use the ISO C and C++
+ // conformant name: _strdup.
+#endif
+
+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.
+//
+
+static 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) {
+ //
+ // Compressible run
+ //
+
+ *outWrite++ = static_cast(runEnd - runStart) - 1;
+ *outWrite++ = *(reinterpret_cast(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++ = static_cast(runStart - runEnd);
+
+ while (runStart < runEnd) {
+ *outWrite++ = *(reinterpret_cast(runStart++));
+ }
+ }
+
+ ++runEnd;
+ }
+
+ return static_cast(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.
+//
+
+static int rleUncompress(int inLength, int maxLength, const signed char in[],
+ char out[]) {
+ char *outStart = out;
+
+ while (inLength > 0) {
+ if (*in < 0) {
+ int count = -(static_cast(*in++));
+ inLength -= count + 1;
+
+ // Fixes #116: Add bounds check to in buffer.
+ if ((0 > (maxLength -= count)) || (inLength < 0)) 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, *reinterpret_cast(in), count + 1);
+ out += count + 1;
+
+ in++;
+ }
+ }
+
+ return static_cast(out - outStart);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// End of RLE code from OpenEXR -----------------------------------
+
+static void CompressRle(unsigned char *dst,
+ tinyexr::tinyexr_uint64 &compressedSize,
+ const unsigned char *src, unsigned long src_size) {
+ std::vector tmpBuf(src_size);
+
+ //
+ // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
+ // ImfRleCompressor.cpp
+ //
+
+ //
+ // Reorder the pixel data.
+ //
+
+ const char *srcPtr = reinterpret_cast(src);
+
+ {
+ char *t1 = reinterpret_cast(&tmpBuf.at(0));
+ char *t2 = reinterpret_cast(&tmpBuf.at(0)) + (src_size + 1) / 2;
+ const char *stop = srcPtr + src_size;
+
+ for (;;) {
+ if (srcPtr < stop)
+ *(t1++) = *(srcPtr++);
+ else
+ break;
+
+ if (srcPtr < stop)
+ *(t2++) = *(srcPtr++);
+ else
+ break;
+ }
+ }
+
+ //
+ // Predictor.
+ //
+
+ {
+ unsigned char *t = &tmpBuf.at(0) + 1;
+ unsigned char *stop = &tmpBuf.at(0) + src_size;
+ int p = t[-1];
+
+ while (t < stop) {
+ int d = int(t[0]) - p + (128 + 256);
+ p = t[0];
+ t[0] = static_cast(d);
+ ++t;
+ }
+ }
+
+ // outSize will be (srcSiz * 3) / 2 at max.
+ int outSize = rleCompress(static_cast(src_size),
+ reinterpret_cast(&tmpBuf.at(0)),
+ reinterpret_cast(dst));
+ assert(outSize > 0);
+
+ compressedSize = static_cast(outSize);
+
+ // Use uncompressed data when compressed data is larger than uncompressed.
+ // (Issue 40)
+ if (compressedSize >= src_size) {
+ compressedSize = src_size;
+ memcpy(dst, src, src_size);
+ }
+}
+
+static bool DecompressRle(unsigned char *dst,
+ const unsigned long uncompressed_size,
+ const unsigned char *src, unsigned long src_size) {
+ if (uncompressed_size == src_size) {
+ // Data is not compressed(Issue 40).
+ memcpy(dst, src, src_size);
+ return true;
+ }
+
+ // Workaround for issue #112.
+ // TODO(syoyo): Add more robust out-of-bounds check in `rleUncompress`.
+ if (src_size <= 2) {
+ return false;
+ }
+
+ std::vector tmpBuf(uncompressed_size);
+
+ int ret = rleUncompress(static_cast(src_size),
+ static_cast(uncompressed_size),
+ reinterpret_cast(src),
+ reinterpret_cast(&tmpBuf.at(0)));
+ if (ret != static_cast(uncompressed_size)) {
+ return false;
+ }
+
+ //
+ // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
+ // ImfRleCompressor.cpp
+ //
+
+ // Predictor.
+ {
+ unsigned char *t = &tmpBuf.at(0) + 1;
+ unsigned char *stop = &tmpBuf.at(0) + uncompressed_size;
+
+ while (t < stop) {
+ int d = int(t[-1]) + int(t[0]) - 128;
+ t[0] = static_cast(d);
+ ++t;
+ }
+ }
+
+ // Reorder the pixel data.
+ {
+ const char *t1 = reinterpret_cast(&tmpBuf.at(0));
+ const char *t2 = reinterpret_cast(&tmpBuf.at(0)) +
+ (uncompressed_size + 1) / 2;
+ char *s = reinterpret_cast(dst);
+ char *stop = s + uncompressed_size;
+
+ for (;;) {
+ if (s < stop)
+ *(s++) = *(t1++);
+ else
+ break;
+
+ if (s < stop)
+ *(s++) = *(t2++);
+ else
+ break;
+ }
+ }
+
+ return true;
+}
+
+#if TINYEXR_USE_PIZ
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+#pragma clang diagnostic ignored "-Wold-style-cast"
+#pragma clang diagnostic ignored "-Wpadded"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wc++11-extensions"
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+
+#if __has_warning("-Wcast-qual")
+#pragma clang diagnostic ignored "-Wcast-qual"
+#endif
+
+#if __has_warning("-Wextra-semi-stmt")
+#pragma clang diagnostic ignored "-Wextra-semi-stmt"
+#endif
+
+#endif
+
+//
+// PIZ compress/uncompress, based on OpenEXR's ImfPizCompressor.cpp
+//
+// -----------------------------------------------------------------
+// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
+// Digital Ltd. LLC)
+// (3 clause BSD license)
+//
+
+struct PIZChannelData {
+ unsigned short *start;
+ unsigned short *end;
+ int nx;
+ int ny;
+ int ys;
+ int size;
+};
+
+//-----------------------------------------------------------------------------
+//
+// 16-bit Haar Wavelet encoding and decoding
+//
+// The source code in this file is derived from the encoding
+// and decoding routines written by Christian Rouet for his
+// PIZ image file format.
+//
+//-----------------------------------------------------------------------------
+
+//
+// Wavelet basis functions without modulo arithmetic; they produce
+// the best compression ratios when the wavelet-transformed data are
+// Huffman-encoded, but the wavelet transform works only for 14-bit
+// data (untransformed data values must be less than (1 << 14)).
+//
+
+inline void wenc14(unsigned short a, unsigned short b, unsigned short &l,
+ unsigned short &h) {
+ short as = static_cast(a);
+ short bs = static_cast(b);
+
+ short ms = (as + bs) >> 1;
+ short ds = as - bs;
+
+ l = static_cast(ms);
+ h = static_cast(ds);
+}
+
+inline void wdec14(unsigned short l, unsigned short h, unsigned short &a,
+ unsigned short &b) {
+ short ls = static_cast(l);
+ short hs = static_cast(h);
+
+ int hi = hs;
+ int ai = ls + (hi & 1) + (hi >> 1);
+
+ short as = static_cast(ai);
+ short bs = static_cast(ai - hi);
+
+ a = static_cast(as);
+ b = static_cast(bs);
+}
+
+//
+// Wavelet basis functions with modulo arithmetic; they work with full
+// 16-bit data, but Huffman-encoding the wavelet-transformed data doesn't
+// compress the data quite as well.
+//
+
+const int NBITS = 16;
+const int A_OFFSET = 1 << (NBITS - 1);
+const int M_OFFSET = 1 << (NBITS - 1);
+const int MOD_MASK = (1 << NBITS) - 1;
+
+inline void wenc16(unsigned short a, unsigned short b, unsigned short &l,
+ unsigned short &h) {
+ int ao = (a + A_OFFSET) & MOD_MASK;
+ int m = ((ao + b) >> 1);
+ int d = ao - b;
+
+ if (d < 0) m = (m + M_OFFSET) & MOD_MASK;
+
+ d &= MOD_MASK;
+
+ l = static_cast(m);
+ h = static_cast(d);
+}
+
+inline void wdec16(unsigned short l, unsigned short h, unsigned short &a,
+ unsigned short &b) {
+ int m = l;
+ int d = h;
+ int bb = (m - (d >> 1)) & MOD_MASK;
+ int aa = (d + bb - A_OFFSET) & MOD_MASK;
+ b = static_cast(bb);
+ a = static_cast(aa);
+}
+
+//
+// 2D Wavelet encoding:
+//
+
+static void wav2Encode(
+ unsigned short *in, // io: values are transformed in place
+ int nx, // i : x size
+ int ox, // i : x offset
+ int ny, // i : y size
+ int oy, // i : y offset
+ unsigned short mx) // i : maximum in[x][y] value
+{
+ bool w14 = (mx < (1 << 14));
+ int n = (nx > ny) ? ny : nx;
+ int p = 1; // == 1 << level
+ int p2 = 2; // == 1 << (level+1)
+
+ //
+ // Hierarchical loop on smaller dimension n
+ //
+
+ 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;
+ }
+}
+
+//
+// 2D Wavelet decoding:
+//
+
+static void wav2Decode(
+ unsigned short *in, // io: values are transformed in place
+ int nx, // i : x size
+ int ox, // i : x offset
+ int ny, // i : y size
+ int oy, // i : y offset
+ unsigned short mx) // i : maximum in[x][y] value
+{
+ bool w14 = (mx < (1 << 14));
+ int n = (nx > ny) ? ny : nx;
+ int p = 1;
+ int p2;
+
+ //
+ // Search max level
+ //
+
+ while (p <= n) p <<= 1;
+
+ p >>= 1;
+ p2 = p;
+ p >>= 1;
+
+ //
+ // Hierarchical loop on smaller dimension n
+ //
+
+ 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;
+ }
+}
+
+//-----------------------------------------------------------------------------
+//
+// 16-bit Huffman compression and decompression.
+//
+// The source code in this file is derived from the 8-bit
+// Huffman compression and decompression routines written
+// by Christian Rouet for his PIZ image file format.
+//
+//-----------------------------------------------------------------------------
+
+// Adds some modification for tinyexr.
+
+const int HUF_ENCBITS = 16; // literal (value) bit length
+const int HUF_DECBITS = 14; // decoding bit size (>= 8)
+
+const int HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1; // encoding table size
+const int HUF_DECSIZE = 1 << HUF_DECBITS; // decoding table size
+const int HUF_DECMASK = HUF_DECSIZE - 1;
+
+struct HufDec { // short code long code
+ //-------------------------------
+ unsigned int len : 8; // code length 0
+ unsigned int lit : 24; // lit p size
+ unsigned int *p; // 0 lits
+};
+
+inline long long hufLength(long long code) { return code & 63; }
+
+inline long long hufCode(long long code) { return code >> 6; }
+
+inline void outputBits(int nBits, long long bits, long long &c, int &lc,
+ char *&out) {
+ c <<= nBits;
+ lc += nBits;
+
+ c |= bits;
+
+ while (lc >= 8) *out++ = static_cast((c >> (lc -= 8)));
+}
+
+inline long long getBits(int nBits, long long &c, int &lc, const char *&in) {
+ while (lc < nBits) {
+ c = (c << 8) | *(reinterpret_cast(in++));
+ lc += 8;
+ }
+
+ lc -= nBits;
+ return (c >> lc) & ((1 << nBits) - 1);
+}
+
+//
+// ENCODING TABLE BUILDING & (UN)PACKING
+//
+
+//
+// Build a "canonical" Huffman code table:
+// - for each (uncompressed) symbol, hcode contains the length
+// of the corresponding code (in the compressed data)
+// - canonical codes are computed and stored in hcode
+// - the rules for constructing canonical codes are as follows:
+// * shorter codes (if filled with zeroes to the right)
+// have a numerically higher value than longer codes
+// * for codes with the same length, numerical values
+// increase with numerical symbol values
+// - because the canonical code table can be constructed from
+// symbol lengths alone, the code table can be transmitted
+// without sending the actual code values
+// - see http://www.compressconsult.com/huffman/
+//
+
+static void hufCanonicalCodeTable(long long hcode[HUF_ENCSIZE]) {
+ long long n[59];
+
+ //
+ // For each i from 0 through 58, count the
+ // number of different codes of length i, and
+ // store the count in n[i].
+ //
+
+ for (int i = 0; i <= 58; ++i) n[i] = 0;
+
+ for (int i = 0; i < HUF_ENCSIZE; ++i) n[hcode[i]] += 1;
+
+ //
+ // For each i from 58 through 1, compute the
+ // numerically lowest code with length i, and
+ // store that code in n[i].
+ //
+
+ long long c = 0;
+
+ for (int i = 58; i > 0; --i) {
+ long long nc = ((c + n[i]) >> 1);
+ n[i] = c;
+ c = nc;
+ }
+
+ //
+ // hcode[i] contains the length, l, of the
+ // code for symbol i. Assign the next available
+ // code of length l to the symbol and store both
+ // l and the code in hcode[i].
+ //
+
+ for (int i = 0; i < HUF_ENCSIZE; ++i) {
+ int l = static_cast(hcode[i]);
+
+ if (l > 0) hcode[i] = l | (n[l]++ << 6);
+ }
+}
+
+//
+// Compute Huffman codes (based on frq input) and store them in frq:
+// - code structure is : [63:lsb - 6:msb] | [5-0: bit length];
+// - max code length is 58 bits;
+// - codes outside the range [im-iM] have a null length (unused values);
+// - original frequencies are destroyed;
+// - encoding tables are used by hufEncode() and hufBuildDecTable();
+//
+
+struct FHeapCompare {
+ bool operator()(long long *a, long long *b) { return *a > *b; }
+};
+
+static void hufBuildEncTable(
+ long long *frq, // io: input frequencies [HUF_ENCSIZE], output table
+ int *im, // o: min frq index
+ int *iM) // o: max frq index
+{
+ //
+ // This function assumes that when it is called, array frq
+ // indicates the frequency of all possible symbols in the data
+ // that are to be Huffman-encoded. (frq[i] contains the number
+ // of occurrences of symbol i in the data.)
+ //
+ // The loop below does three things:
+ //
+ // 1) Finds the minimum and maximum indices that point
+ // to non-zero entries in frq:
+ //
+ // frq[im] != 0, and frq[i] == 0 for all i < im
+ // frq[iM] != 0, and frq[i] == 0 for all i > iM
+ //
+ // 2) Fills array fHeap with pointers to all non-zero
+ // entries in frq.
+ //
+ // 3) Initializes array hlink such that hlink[i] == i
+ // for all array entries.
+ //
+
+ std::vector hlink(HUF_ENCSIZE);
+ std::vector fHeap(HUF_ENCSIZE);
+
+ *im = 0;
+
+ while (!frq[*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;
+ }
+ }
+
+ //
+ // Add a pseudo-symbol, with a frequency count of 1, to frq;
+ // adjust the fHeap and hlink array accordingly. Function
+ // hufEncode() uses the pseudo-symbol for run-length encoding.
+ //
+
+ (*iM)++;
+ frq[*iM] = 1;
+ fHeap[nf] = &frq[*iM];
+ nf++;
+
+ //
+ // Build an array, scode, such that scode[i] contains the number
+ // of bits assigned to symbol i. Conceptually this is done by
+ // constructing a tree whose leaves are the symbols with non-zero
+ // frequency:
+ //
+ // Make a heap that contains all symbols with a non-zero frequency,
+ // with the least frequent symbol on top.
+ //
+ // Repeat until only one symbol is left on the heap:
+ //
+ // Take the two least frequent symbols off the top of the heap.
+ // Create a new node that has first two nodes as children, and
+ // whose frequency is the sum of the frequencies of the first
+ // two nodes. Put the new node back into the heap.
+ //
+ // The last node left on the heap is the root of the tree. For each
+ // leaf node, the distance between the root and the leaf is the length
+ // of the code for the corresponding symbol.
+ //
+ // The loop below doesn't actually build the tree; instead we compute
+ // the distances of the leaves from the root on the fly. When a new
+ // node is added to the heap, then that node's descendants are linked
+ // into a single linear list that starts at the new node, and the code
+ // lengths of the descendants (that is, their distance from the root
+ // of the tree) are incremented by one.
+ //
+
+ std::make_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
+
+ std::vector scode(HUF_ENCSIZE);
+ memset(scode.data(), 0, sizeof(long long) * HUF_ENCSIZE);
+
+ 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;
+ std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
+ --nf;
+
+ int m = fHeap[0] - frq;
+ std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
+
+ frq[m] += frq[mm];
+ std::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;; 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;; j = hlink[j]) {
+ scode[j]++;
+
+ assert(scode[j] <= 58);
+
+ if (hlink[j] == j) break;
+ }
+ }
+
+ //
+ // Build a canonical Huffman code table, replacing the code
+ // lengths in scode with (code, code length) pairs. Copy the
+ // code table from scode into frq.
+ //
+
+ hufCanonicalCodeTable(scode.data());
+ memcpy(frq, scode.data(), sizeof(long long) * HUF_ENCSIZE);
+}
+
+//
+// Pack an encoding table:
+// - only code lengths, not actual codes, are stored
+// - runs of zeroes are compressed as follows:
+//
+// unpacked packed
+// --------------------------------
+// 1 zero 0 (6 bits)
+// 2 zeroes 59
+// 3 zeroes 60
+// 4 zeroes 61
+// 5 zeroes 62
+// n zeroes (6 or more) 63 n-6 (6 + 8 bits)
+//
+
+const int SHORT_ZEROCODE_RUN = 59;
+const int LONG_ZEROCODE_RUN = 63;
+const int SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN;
+const int LONGEST_LONG_RUN = 255 + SHORTEST_LONG_RUN;
+
+static void hufPackEncTable(
+ const long long *hcode, // i : encoding table [HUF_ENCSIZE]
+ int im, // i : min hcode index
+ int iM, // i : max hcode index
+ char **pcode) // o: ptr to packed table (updated)
+{
+ char *p = *pcode;
+ long long c = 0;
+ int lc = 0;
+
+ 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);
+ }
+
+ if (lc > 0) *p++ = (unsigned char)(c << (8 - lc));
+
+ *pcode = p;
+}
+
+//
+// Unpack an encoding table packed by hufPackEncTable():
+//
+
+static bool hufUnpackEncTable(
+ const char **pcode, // io: ptr to packed table (updated)
+ int ni, // i : input size (in bytes)
+ int im, // i : min hcode index
+ int iM, // i : max hcode index
+ long long *hcode) // o: encoding table [HUF_ENCSIZE]
+{
+ memset(hcode, 0, sizeof(long long) * HUF_ENCSIZE);
+
+ const char *p = *pcode;
+ long long c = 0;
+ int lc = 0;
+
+ for (; im <= iM; im++) {
+ if (p - *pcode >= ni) {
+ return false;
+ }
+
+ long long l = hcode[im] = getBits(6, c, lc, p); // code length
+
+ if (l == (long long)LONG_ZEROCODE_RUN) {
+ if (p - *pcode > ni) {
+ return false;
+ }
+
+ int zerun = getBits(8, c, lc, p) + SHORTEST_LONG_RUN;
+
+ if (im + zerun > iM + 1) {
+ return false;
+ }
+
+ while (zerun--) hcode[im++] = 0;
+
+ im--;
+ } else if (l >= (long long)SHORT_ZEROCODE_RUN) {
+ int zerun = l - SHORT_ZEROCODE_RUN + 2;
+
+ if (im + zerun > iM + 1) {
+ return false;
+ }
+
+ while (zerun--) hcode[im++] = 0;
+
+ im--;
+ }
+ }
+
+ *pcode = const_cast(p);
+
+ hufCanonicalCodeTable(hcode);
+
+ return true;
+}
+
+//
+// DECODING TABLE BUILDING
+//
+
+//
+// Clear a newly allocated decoding table so that it contains only zeroes.
+//
+
+static void hufClearDecTable(HufDec *hdecod) // io: (allocated by caller)
+// decoding table [HUF_DECSIZE]
+{
+ for (int i = 0; i < HUF_DECSIZE; i++) {
+ hdecod[i].len = 0;
+ hdecod[i].lit = 0;
+ hdecod[i].p = NULL;
+ }
+ // memset(hdecod, 0, sizeof(HufDec) * HUF_DECSIZE);
+}
+
+//
+// Build a decoding hash table based on the encoding table hcode:
+// - short codes (<= HUF_DECBITS) are resolved with a single table access;
+// - long code entry allocations are not optimized, because long codes are
+// unfrequent;
+// - decoding tables are used by hufDecode();
+//
+
+static bool hufBuildDecTable(const long long *hcode, // i : encoding table
+ int im, // i : min index in hcode
+ int iM, // i : max index in hcode
+ HufDec *hdecod) // o: (allocated by caller)
+// decoding table [HUF_DECSIZE]
+{
+ //
+ // Init hashtable & loop on all codes.
+ // Assumes that hufClearDecTable(hdecod) has already been called.
+ //
+
+ for (; im <= iM; im++) {
+ long long 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();
+ return false;
+ }
+
+ 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();
+ return false;
+ }
+
+ pl->lit++;
+
+ if (pl->p) {
+ unsigned int *p = pl->p;
+ pl->p = new unsigned int[pl->lit];
+
+ for (int i = 0; i < pl->lit - 1; ++i) pl->p[i] = p[i];
+
+ delete[] p;
+ } else {
+ pl->p = new unsigned 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 (long long i = 1ULL << (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();
+ return false;
+ }
+
+ pl->len = l;
+ pl->lit = im;
+ }
+ }
+ }
+
+ return true;
+}
+
+//
+// Free the long code entries of a decoding table built by hufBuildDecTable()
+//
+
+static void hufFreeDecTable(HufDec *hdecod) // io: Decoding table
+{
+ for (int i = 0; i < HUF_DECSIZE; i++) {
+ if (hdecod[i].p) {
+ delete[] hdecod[i].p;
+ hdecod[i].p = 0;
+ }
+ }
+}
+
+//
+// ENCODING
+//
+
+inline void outputCode(long long code, long long &c, int &lc, char *&out) {
+ outputBits(hufLength(code), hufCode(code), c, lc, out);
+}
+
+inline void sendCode(long long sCode, int runCount, long long runCode,
+ long long &c, int &lc, char *&out) {
+ //
+ // 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);
+ } else {
+ while (runCount-- >= 0) outputCode(sCode, c, lc, out);
+ }
+}
+
+//
+// Encode (compress) ni values based on the Huffman encoding table hcode:
+//
+
+static int hufEncode // return: output size (in bits)
+ (const long long *hcode, // i : encoding table
+ const unsigned short *in, // i : uncompressed input buffer
+ const int ni, // i : input buffer size (in bytes)
+ int rlc, // i : rl code
+ char *out) // o: compressed output buffer
+{
+ char *outStart = out;
+ long long c = 0; // bits not yet written to out
+ int lc = 0; // number of valid bits in c (LSB)
+ int s = in[0];
+ int cs = 0;
+
+ //
+ // Loop on input values
+ //
+
+ 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];
+ }
+
+ //
+ // Send remaining code
+ //
+
+ sendCode(hcode[s], cs, hcode[rlc], c, lc, out);
+
+ if (lc) *out = (c << (8 - lc)) & 0xff;
+
+ return (out - outStart) * 8 + lc;
+}
+
+//
+// DECODING
+//
+
+//
+// In order to force the compiler to inline them,
+// getChar() and getCode() are implemented as macros
+// instead of "inline" functions.
+//
+
+#define getChar(c, lc, in) \
+ { \
+ c = (c << 8) | *(unsigned char *)(in++); \
+ lc += 8; \
+ }
+
+#if 0
+#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) return false; \
+ \
+ /* TinyEXR issue 78 */ \
+ unsigned short s = out[-1]; \
+ \
+ while (cs-- > 0) *out++ = s; \
+ } else if (out < oe) { \
+ *out++ = po; \
+ } else { \
+ return false; \
+ } \
+ }
+#else
+static bool getCode(int po, int rlc, long long &c, int &lc, const char *&in,
+ const char *in_end, unsigned short *&out,
+ const unsigned short *ob, const unsigned short *oe) {
+ (void)ob;
+ if (po == rlc) {
+ if (lc < 8) {
+ /* TinyEXR issue 78 */
+ /* TinyEXR issue 160. in + 1 -> in */
+ if (in >= in_end) {
+ return false;
+ }
+
+ getChar(c, lc, in);
+ }
+
+ lc -= 8;
+
+ unsigned char cs = (c >> lc);
+
+ if (out + cs > oe) return false;
+
+ // Bounds check for safety
+ // Issue 100.
+ if ((out - 1) < ob) return false;
+ unsigned short s = out[-1];
+
+ while (cs-- > 0) *out++ = s;
+ } else if (out < oe) {
+ *out++ = po;
+ } else {
+ return false;
+ }
+ return true;
+}
+#endif
+
+//
+// Decode (uncompress) ni bits based on encoding & decoding tables:
+//
+
+static bool hufDecode(const long long *hcode, // i : encoding table
+ const HufDec *hdecod, // i : decoding table
+ const char *in, // i : compressed input buffer
+ int ni, // i : input size (in bits)
+ int rlc, // i : run-length code
+ int no, // i : expected output size (in bytes)
+ unsigned short *out) // o: uncompressed output buffer
+{
+ long long c = 0;
+ int lc = 0;
+ unsigned short *outb = out; // begin
+ unsigned short *oe = out + no; // end
+ const char *ie = in + (ni + 7) / 8; // input byte size
+
+ //
+ // Loop on input bytes
+ //
+
+ 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;
+ // std::cout << "lit = " << pl.lit << std::endl;
+ // std::cout << "rlc = " << rlc << std::endl;
+ // std::cout << "c = " << c << std::endl;
+ // std::cout << "lc = " << lc << std::endl;
+ // std::cout << "in = " << in << std::endl;
+ // std::cout << "out = " << out << std::endl;
+ // std::cout << "oe = " << oe << std::endl;
+ if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
+ return false;
+ }
+ } else {
+ if (!pl.p) {
+ return false;
+ }
+ // 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)) & (((long long)(1) << l) - 1))) {
+ //
+ // Found : get long code
+ //
+
+ lc -= l;
+ if (!getCode(pl.p[j], rlc, c, lc, in, ie, out, outb, oe)) {
+ return false;
+ }
+ break;
+ }
+ }
+ }
+
+ if (j == pl.lit) {
+ return false;
+ // invalidCode(); // Not found
+ }
+ }
+ }
+ }
+
+ //
+ // Get remaining (short) codes
+ //
+
+ int i = (8 - ni) & 7;
+ c >>= i;
+ lc -= i;
+
+ while (lc > 0) {
+ const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
+
+ if (pl.len) {
+ lc -= pl.len;
+ if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
+ return false;
+ }
+ } else {
+ return false;
+ // invalidCode(); // wrong (long) code
+ }
+ }
+
+ if (out - outb != no) {
+ return false;
+ }
+ // notEnoughData ();
+
+ return true;
+}
+
+static void countFrequencies(std::vector &freq,
+ const unsigned short data[/*n*/], int n) {
+ for (int i = 0; i < HUF_ENCSIZE; ++i) freq[i] = 0;
+
+ for (int i = 0; i < n; ++i) ++freq[data[i]];
+}
+
+static void writeUInt(char buf[4], unsigned int i) {
+ unsigned char *b = (unsigned char *)buf;
+
+ b[0] = i;
+ b[1] = i >> 8;
+ b[2] = i >> 16;
+ b[3] = i >> 24;
+}
+
+static unsigned int readUInt(const char buf[4]) {
+ const unsigned char *b = (const unsigned char *)buf;
+
+ return (b[0] & 0x000000ff) | ((b[1] << 8) & 0x0000ff00) |
+ ((b[2] << 16) & 0x00ff0000) | ((b[3] << 24) & 0xff000000);
+}
+
+//
+// EXTERNAL INTERFACE
+//
+
+static int hufCompress(const unsigned short raw[], int nRaw,
+ char compressed[]) {
+ if (nRaw == 0) return 0;
+
+ std::vector freq(HUF_ENCSIZE);
+
+ countFrequencies(freq, raw, nRaw);
+
+ int im = 0;
+ int iM = 0;
+ hufBuildEncTable(freq.data(), &im, &iM);
+
+ char *tableStart = compressed + 20;
+ char *tableEnd = tableStart;
+ hufPackEncTable(freq.data(), im, iM, &tableEnd);
+ int tableLength = tableEnd - tableStart;
+
+ char *dataStart = tableEnd;
+ int nBits = hufEncode(freq.data(), raw, nRaw, iM, dataStart);
+ int data_length = (nBits + 7) / 8;
+
+ writeUInt(compressed, im);
+ writeUInt(compressed + 4, iM);
+ writeUInt(compressed + 8, tableLength);
+ writeUInt(compressed + 12, nBits);
+ writeUInt(compressed + 16, 0); // room for future extensions
+
+ return dataStart + data_length - compressed;
+}
+
+static bool hufUncompress(const char compressed[], int nCompressed,
+ std::vector *raw) {
+ if (nCompressed == 0) {
+ if (raw->size() != 0) return false;
+
+ return false;
+ }
+
+ int im = readUInt(compressed);
+ int iM = readUInt(compressed + 4);
+ // int tableLength = readUInt (compressed + 8);
+ int nBits = readUInt(compressed + 12);
+
+ if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) return false;
+
+ const char *ptr = compressed + 20;
+
+ //
+ // 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
+ //
+
+ // if (FastHufDecoder::enabled() && nBits > 128)
+ //{
+ // FastHufDecoder fhd (ptr, nCompressed - (ptr - compressed), im, iM, iM);
+ // fhd.decode ((unsigned char*)ptr, nBits, raw, nRaw);
+ //}
+ // else
+ {
+ std::vector freq(HUF_ENCSIZE);
+ std::vector hdec(HUF_DECSIZE);
+
+ hufClearDecTable(&hdec.at(0));
+
+ hufUnpackEncTable(&ptr, nCompressed - (ptr - compressed), im, iM,
+ &freq.at(0));
+
+ {
+ if (nBits > 8 * (nCompressed - (ptr - compressed))) {
+ return false;
+ }
+
+ hufBuildDecTable(&freq.at(0), im, iM, &hdec.at(0));
+ hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, raw->size(),
+ raw->data());
+ }
+ // catch (...)
+ //{
+ // hufFreeDecTable (hdec);
+ // throw;
+ //}
+
+ hufFreeDecTable(&hdec.at(0));
+ }
+
+ return true;
+}
+
+//
+// Functions to compress the range of values in the pixel data
+//
+
+const int USHORT_RANGE = (1 << 16);
+const int BITMAP_SIZE = (USHORT_RANGE >> 3);
+
+static void bitmapFromData(const unsigned short data[/*nData*/], int nData,
+ unsigned char bitmap[BITMAP_SIZE],
+ unsigned short &minNonZero,
+ unsigned short &maxNonZero) {
+ for (int i = 0; i < BITMAP_SIZE; ++i) bitmap[i] = 0;
+
+ for (int i = 0; i < nData; ++i) 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
+ 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;
+ }
+ }
+}
+
+static unsigned short forwardLutFromBitmap(
+ const unsigned char bitmap[BITMAP_SIZE], 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;
+ }
+
+ return k - 1; // maximum value stored in lut[],
+} // i.e. number of ones in bitmap minus 1
+
+static unsigned short reverseLutFromBitmap(
+ const unsigned char bitmap[BITMAP_SIZE], 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;
+ }
+
+ int n = k - 1;
+
+ while (k < USHORT_RANGE) lut[k++] = 0;
+
+ return n; // maximum k where lut[k] is non-zero,
+} // i.e. number of ones in bitmap minus 1
+
+static void applyLut(const unsigned short lut[USHORT_RANGE],
+ unsigned short data[/*nData*/], int nData) {
+ for (int i = 0; i < nData; ++i) data[i] = lut[data[i]];
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif // __clang__
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
+ const unsigned char *inPtr, size_t inSize,
+ const std::vector &channelInfo,
+ int data_width, int num_lines) {
+ std::vector bitmap(BITMAP_SIZE);
+ unsigned short minNonZero;
+ unsigned short maxNonZero;
+
+#if !TINYEXR_LITTLE_ENDIAN
+ // @todo { PIZ compression on BigEndian architecture. }
+ assert(0);
+ return false;
+#endif
+
+ // Assume `inSize` is multiple of 2 or 4.
+ std::vector tmpBuffer(inSize / sizeof(unsigned short));
+
+ std::vector channelData(channelInfo.size());
+ unsigned short *tmpBufferEnd = &tmpBuffer.at(0);
+
+ for (size_t c = 0; c < channelData.size(); c++) {
+ PIZChannelData &cd = channelData[c];
+
+ cd.start = tmpBufferEnd;
+ cd.end = cd.start;
+
+ cd.nx = data_width;
+ cd.ny = num_lines;
+ // cd.ys = c.channel().ySampling;
+
+ size_t pixelSize = sizeof(int); // UINT and FLOAT
+ if (channelInfo[c].requested_pixel_type == TINYEXR_PIXELTYPE_HALF) {
+ pixelSize = sizeof(short);
+ }
+
+ cd.size = static_cast(pixelSize / sizeof(short));
+
+ tmpBufferEnd += cd.nx * cd.ny * cd.size;
+ }
+
+ const unsigned char *ptr = inPtr;
+ for (int y = 0; y < num_lines; ++y) {
+ for (size_t i = 0; i < channelData.size(); ++i) {
+ PIZChannelData &cd = channelData[i];
+
+ // if (modp (y, cd.ys) != 0)
+ // continue;
+
+ size_t n = static_cast(cd.nx * cd.size);
+ memcpy(cd.end, ptr, n * sizeof(unsigned short));
+ ptr += n * sizeof(unsigned short);
+ cd.end += n;
+ }
+ }
+
+ bitmapFromData(&tmpBuffer.at(0), static_cast(tmpBuffer.size()),
+ bitmap.data(), minNonZero, maxNonZero);
+
+ std::vector lut(USHORT_RANGE);
+ unsigned short maxValue = forwardLutFromBitmap(bitmap.data(), lut.data());
+ applyLut(lut.data(), &tmpBuffer.at(0), static_cast(tmpBuffer.size()));
+
+ //
+ // Store range compression info in _outBuffer
+ //
+
+ char *buf = reinterpret_cast(outPtr);
+
+ memcpy(buf, &minNonZero, sizeof(unsigned short));
+ buf += sizeof(unsigned short);
+ memcpy(buf, &maxNonZero, sizeof(unsigned short));
+ buf += sizeof(unsigned short);
+
+ if (minNonZero <= maxNonZero) {
+ memcpy(buf, reinterpret_cast(&bitmap[0] + minNonZero),
+ maxNonZero - minNonZero + 1);
+ buf += maxNonZero - minNonZero + 1;
+ }
+
+ //
+ // Apply wavelet encoding
+ //
+
+ for (size_t i = 0; i < channelData.size(); ++i) {
+ PIZChannelData &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);
+ }
+ }
+
+ //
+ // Apply Huffman encoding; append the result to _outBuffer
+ //
+
+ // length header(4byte), then huff data. Initialize length header with zero,
+ // then later fill it by `length`.
+ char *lengthPtr = buf;
+ int zero = 0;
+ memcpy(buf, &zero, sizeof(int));
+ buf += sizeof(int);
+
+ int length =
+ hufCompress(&tmpBuffer.at(0), static_cast(tmpBuffer.size()), buf);
+ memcpy(lengthPtr, &length, sizeof(int));
+
+ (*outSize) = static_cast(
+ (reinterpret_cast(buf) - outPtr) +
+ static_cast(length));
+
+ // Use uncompressed data when compressed data is larger than uncompressed.
+ // (Issue 40)
+ if ((*outSize) >= inSize) {
+ (*outSize) = static_cast(inSize);
+ memcpy(outPtr, inPtr, inSize);
+ }
+ return true;
+}
+
+static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
+ size_t tmpBufSizeInBytes, size_t inLen, int num_channels,
+ const EXRChannelInfo *channels, int data_width,
+ int num_lines) {
+ if (inLen == tmpBufSizeInBytes) {
+ // Data is not compressed(Issue 40).
+ memcpy(outPtr, inPtr, inLen);
+ return true;
+ }
+
+ std::vector bitmap(BITMAP_SIZE);
+ unsigned short minNonZero;
+ unsigned short maxNonZero;
+
+#if !TINYEXR_LITTLE_ENDIAN
+ // @todo { PIZ compression on BigEndian architecture. }
+ assert(0);
+ return false;
+#endif
+
+ memset(bitmap.data(), 0, BITMAP_SIZE);
+
+ const unsigned char *ptr = inPtr;
+ // minNonZero = *(reinterpret_cast(ptr));
+ tinyexr::cpy2(&minNonZero, reinterpret_cast(ptr));
+ // maxNonZero = *(reinterpret_cast(ptr + 2));
+ tinyexr::cpy2(&maxNonZero, reinterpret_cast(ptr + 2));
+ ptr += 4;
+
+ if (maxNonZero >= BITMAP_SIZE) {
+ return false;
+ }
+
+ if (minNonZero <= maxNonZero) {
+ memcpy(reinterpret_cast(&bitmap[0] + minNonZero), ptr,
+ maxNonZero - minNonZero + 1);
+ ptr += maxNonZero - minNonZero + 1;
+ }
+
+ std::vector lut(USHORT_RANGE);
+ memset(lut.data(), 0, sizeof(unsigned short) * USHORT_RANGE);
+ unsigned short maxValue = reverseLutFromBitmap(bitmap.data(), lut.data());
+
+ //
+ // Huffman decoding
+ //
+
+ int length;
+
+ // length = *(reinterpret_cast(ptr));
+ tinyexr::cpy4(&length, reinterpret_cast(ptr));
+ ptr += sizeof(int);
+
+ if (size_t((ptr - inPtr) + length) > inLen) {
+ return false;
+ }
+
+ std::vector tmpBuffer(tmpBufSizeInBytes / sizeof(unsigned short));
+ hufUncompress(reinterpret_cast(ptr), length, &tmpBuffer);
+
+ //
+ // Wavelet decoding
+ //
+
+ std::vector channelData(static_cast(num_channels));
+
+ unsigned short *tmpBufferEnd = &tmpBuffer.at(0);
+
+ for (size_t i = 0; i < static_cast(num_channels); ++i) {
+ const EXRChannelInfo &chan = channels[i];
+
+ size_t pixelSize = sizeof(int); // UINT and FLOAT
+ if (chan.pixel_type == TINYEXR_PIXELTYPE_HALF) {
+ pixelSize = sizeof(short);
+ }
+
+ channelData[i].start = tmpBufferEnd;
+ channelData[i].end = channelData[i].start;
+ channelData[i].nx = data_width;
+ channelData[i].ny = num_lines;
+ // channelData[i].ys = 1;
+ channelData[i].size = static_cast(pixelSize / sizeof(short));
+
+ tmpBufferEnd += channelData[i].nx * channelData[i].ny * channelData[i].size;
+ }
+
+ for (size_t i = 0; i < channelData.size(); ++i) {
+ PIZChannelData &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);
+ }
+ }
+
+ //
+ // Expand the pixel data to their original range
+ //
+
+ applyLut(lut.data(), &tmpBuffer.at(0), static_cast(tmpBufSizeInBytes / sizeof(unsigned short)));
+
+ for (int y = 0; y < num_lines; y++) {
+ for (size_t i = 0; i < channelData.size(); ++i) {
+ PIZChannelData &cd = channelData[i];
+
+ // if (modp (y, cd.ys) != 0)
+ // continue;
+
+ size_t n = static_cast(cd.nx * cd.size);
+ memcpy(outPtr, cd.end, static_cast(n * sizeof(unsigned short)));
+ outPtr += n * sizeof(unsigned short);
+ cd.end += n;
+ }
+ }
+
+ return true;
+}
+#endif // TINYEXR_USE_PIZ
+
+#if TINYEXR_USE_ZFP
+
+struct ZFPCompressionParam {
+ double rate;
+ unsigned int precision;
+ unsigned int __pad0;
+ double tolerance;
+ int type; // TINYEXR_ZFP_COMPRESSIONTYPE_*
+ unsigned int __pad1;
+
+ ZFPCompressionParam() {
+ type = TINYEXR_ZFP_COMPRESSIONTYPE_RATE;
+ rate = 2.0;
+ precision = 0;
+ tolerance = 0.0;
+ }
+};
+
+static bool FindZFPCompressionParam(ZFPCompressionParam *param,
+ const EXRAttribute *attributes,
+ int num_attributes, std::string *err) {
+ bool foundType = false;
+
+ for (int i = 0; i < num_attributes; i++) {
+ if ((strcmp(attributes[i].name, "zfpCompressionType") == 0)) {
+ if (attributes[i].size == 1) {
+ param->type = static_cast(attributes[i].value[0]);
+ foundType = true;
+ break;
+ } else {
+ if (err) {
+ (*err) +=
+ "zfpCompressionType attribute must be uchar(1 byte) type.\n";
+ }
+ return false;
+ }
+ }
+ }
+
+ if (!foundType) {
+ if (err) {
+ (*err) += "`zfpCompressionType` attribute not found.\n";
+ }
+ return false;
+ }
+
+ if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
+ for (int i = 0; i < num_attributes; i++) {
+ if ((strcmp(attributes[i].name, "zfpCompressionRate") == 0) &&
+ (attributes[i].size == 8)) {
+ param->rate = *(reinterpret_cast(attributes[i].value));
+ return true;
+ }
+ }
+
+ if (err) {
+ (*err) += "`zfpCompressionRate` attribute not found.\n";
+ }
+
+ } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
+ for (int i = 0; i < num_attributes; i++) {
+ if ((strcmp(attributes[i].name, "zfpCompressionPrecision") == 0) &&
+ (attributes[i].size == 4)) {
+ param->rate = *(reinterpret_cast(attributes[i].value));
+ return true;
+ }
+ }
+
+ if (err) {
+ (*err) += "`zfpCompressionPrecision` attribute not found.\n";
+ }
+
+ } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
+ for (int i = 0; i < num_attributes; i++) {
+ if ((strcmp(attributes[i].name, "zfpCompressionTolerance") == 0) &&
+ (attributes[i].size == 8)) {
+ param->tolerance = *(reinterpret_cast(attributes[i].value));
+ return true;
+ }
+ }
+
+ if (err) {
+ (*err) += "`zfpCompressionTolerance` attribute not found.\n";
+ }
+ } else {
+ if (err) {
+ (*err) += "Unknown value specified for `zfpCompressionType`.\n";
+ }
+ }
+
+ return false;
+}
+
+// Assume pixel format is FLOAT for all channels.
+static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines,
+ size_t num_channels, const unsigned char *src,
+ unsigned long src_size,
+ const ZFPCompressionParam ¶m) {
+ size_t uncompressed_size =
+ size_t(dst_width) * size_t(dst_num_lines) * num_channels;
+
+ if (uncompressed_size == src_size) {
+ // Data is not compressed(Issue 40).
+ memcpy(dst, src, src_size);
+ }
+
+ zfp_stream *zfp = NULL;
+ zfp_field *field = NULL;
+
+ assert((dst_width % 4) == 0);
+ assert((dst_num_lines % 4) == 0);
+
+ if ((size_t(dst_width) & 3U) || (size_t(dst_num_lines) & 3U)) {
+ return false;
+ }
+
+ field =
+ zfp_field_2d(reinterpret_cast(const_cast(src)),
+ zfp_type_float, static_cast(dst_width),
+ static_cast(dst_num_lines) *
+ static_cast(num_channels));
+ zfp = zfp_stream_open(NULL);
+
+ if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
+ zfp_stream_set_rate(zfp, param.rate, zfp_type_float, /* dimension */ 2,
+ /* write random access */ 0);
+ } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
+ zfp_stream_set_precision(zfp, param.precision);
+ } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
+ zfp_stream_set_accuracy(zfp, param.tolerance);
+ } else {
+ assert(0);
+ }
+
+ size_t buf_size = zfp_stream_maximum_size(zfp, field);
+ std::vector buf(buf_size);
+ memcpy(&buf.at(0), src, src_size);
+
+ bitstream *stream = stream_open(&buf.at(0), buf_size);
+ zfp_stream_set_bit_stream(zfp, stream);
+ zfp_stream_rewind(zfp);
+
+ size_t image_size = size_t(dst_width) * size_t(dst_num_lines);
+
+ for (size_t c = 0; c < size_t(num_channels); c++) {
+ // decompress 4x4 pixel block.
+ for (size_t y = 0; y < size_t(dst_num_lines); y += 4) {
+ for (size_t x = 0; x < size_t(dst_width); x += 4) {
+ float fblock[16];
+ zfp_decode_block_float_2(zfp, fblock);
+ for (size_t j = 0; j < 4; j++) {
+ for (size_t i = 0; i < 4; i++) {
+ dst[c * image_size + ((y + j) * size_t(dst_width) + (x + i))] =
+ fblock[j * 4 + i];
+ }
+ }
+ }
+ }
+ }
+
+ zfp_field_free(field);
+ zfp_stream_close(zfp);
+ stream_close(stream);
+
+ return true;
+}
+
+// Assume pixel format is FLOAT for all channels.
+static bool CompressZfp(std::vector *outBuf,
+ unsigned int *outSize, const float *inPtr, int width,
+ int num_lines, int num_channels,
+ const ZFPCompressionParam ¶m) {
+ zfp_stream *zfp = NULL;
+ zfp_field *field = NULL;
+
+ assert((width % 4) == 0);
+ assert((num_lines % 4) == 0);
+
+ if ((size_t(width) & 3U) || (size_t(num_lines) & 3U)) {
+ return false;
+ }
+
+ // create input array.
+ field = zfp_field_2d(reinterpret_cast(const_cast(inPtr)),
+ zfp_type_float, static_cast(width),
+ static_cast(num_lines * num_channels));
+
+ zfp = zfp_stream_open(NULL);
+
+ if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
+ zfp_stream_set_rate(zfp, param.rate, zfp_type_float, 2, 0);
+ } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
+ zfp_stream_set_precision(zfp, param.precision);
+ } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
+ zfp_stream_set_accuracy(zfp, param.tolerance);
+ } else {
+ assert(0);
+ }
+
+ size_t buf_size = zfp_stream_maximum_size(zfp, field);
+
+ outBuf->resize(buf_size);
+
+ bitstream *stream = stream_open(&outBuf->at(0), buf_size);
+ zfp_stream_set_bit_stream(zfp, stream);
+ zfp_field_free(field);
+
+ size_t image_size = size_t(width) * size_t(num_lines);
+
+ for (size_t c = 0; c < size_t(num_channels); c++) {
+ // compress 4x4 pixel block.
+ for (size_t y = 0; y < size_t(num_lines); y += 4) {
+ for (size_t x = 0; x < size_t(width); x += 4) {
+ float fblock[16];
+ for (size_t j = 0; j < 4; j++) {
+ for (size_t i = 0; i < 4; i++) {
+ fblock[j * 4 + i] =
+ inPtr[c * image_size + ((y + j) * size_t(width) + (x + i))];
+ }
+ }
+ zfp_encode_block_float_2(zfp, fblock);
+ }
+ }
+ }
+
+ zfp_stream_flush(zfp);
+ (*outSize) = static_cast(zfp_stream_compressed_size(zfp));
+
+ zfp_stream_close(zfp);
+
+ return true;
+}
+
+#endif
+
+//
+// -----------------------------------------------------------------
+//
+
+// heuristics
+#define TINYEXR_DIMENSION_THRESHOLD (1024 * 8192)
+
+// TODO(syoyo): Refactor function arguments.
+static bool DecodePixelData(/* out */ unsigned char **out_images,
+ const int *requested_pixel_types,
+ const unsigned char *data_ptr, size_t data_len,
+ int compression_type, int line_order, int width,
+ int height, int x_stride, int y, int line_no,
+ int num_lines, size_t pixel_data_size,
+ size_t num_attributes,
+ const EXRAttribute *attributes, size_t num_channels,
+ const EXRChannelInfo *channels,
+ const std::vector &channel_offset_list) {
+ if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { // PIZ
+#if TINYEXR_USE_PIZ
+ if ((width == 0) || (num_lines == 0) || (pixel_data_size == 0)) {
+ // Invalid input #90
+ return false;
+ }
+
+ // Allocate original data size.
+ std::vector outBuf(static_cast(
+ static_cast(width * num_lines) * pixel_data_size));
+ size_t tmpBufLen = outBuf.size();
+
+ bool ret = tinyexr::DecompressPiz(
+ reinterpret_cast(&outBuf.at(0)), data_ptr, tmpBufLen,
+ data_len, static_cast(num_channels), channels, width, num_lines);
+
+ if (!ret) {
+ return false;
+ }
+
+ // For PIZ_COMPRESSION:
+ // pixel sample data for channel 0 for scanline 0
+ // pixel sample data for channel 1 for scanline 0
+ // pixel sample data for channel ... for scanline 0
+ // pixel sample data for channel n for scanline 0
+ // pixel sample data for channel 0 for scanline 1
+ // pixel sample data for channel 1 for scanline 1
+ // pixel sample data for channel ... for scanline 1
+ // pixel sample data for channel n for scanline 1
+ // ...
+ for (size_t c = 0; c < static_cast(num_channels); c++) {
+ if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
+ for (size_t v = 0; v < static_cast(num_lines); v++) {
+ const unsigned short *line_ptr = reinterpret_cast(
+ &outBuf.at(v * pixel_data_size * static_cast(width) +
+ channel_offset_list[c] * static_cast(width)));
+ for (size_t u = 0; u < static_cast(width); u++) {
+ FP16 hf;
+
+ // hf.u = line_ptr[u];
+ // use `cpy` to avoid unaligned memory access when compiler's
+ // optimization is on.
+ tinyexr::cpy2(&(hf.u), line_ptr + u);
+
+ tinyexr::swap2(reinterpret_cast(&hf.u));
+
+ if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
+ unsigned short *image =
+ reinterpret_cast(out_images)[c];
+ if (line_order == 0) {
+ image += (static_cast(line_no) + v) *
+ static_cast(x_stride) +
+ u;
+ } else {
+ image += static_cast(
+ (height - 1 - (line_no + static_cast(v)))) *
+ static_cast(x_stride) +
+ u;
+ }
+ *image = hf.u;
+ } else { // HALF -> FLOAT
+ FP32 f32 = half_to_float(hf);
+ float *image = reinterpret_cast(out_images)[c];
+ size_t offset = 0;
+ if (line_order == 0) {
+ offset = (static_cast(line_no) + v) *
+ static_cast(x_stride) +
+ u;
+ } else {
+ offset = static_cast(
+ (height - 1 - (line_no + static_cast(v)))) *
+ static_cast(x_stride) +
+ u;
+ }
+ image += offset;
+ *image = f32.f;
+ }
+ }
+ }
+ } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
+ assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
+
+ for (size_t v = 0; v < static_cast(num_lines); v++) {
+ const unsigned int *line_ptr = reinterpret_cast(
+ &outBuf.at(v * pixel_data_size * static_cast(width) +
+ channel_offset_list[c] * static_cast(width)));
+ for (size_t u = 0; u < static_cast(width); u++) {
+ unsigned int val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
+
+ tinyexr::swap4(&val);
+
+ unsigned int *image =
+ reinterpret_cast(out_images)[c];
+ if (line_order == 0) {
+ image += (static_cast(line_no) + v) *
+ static_cast(x_stride) +
+ u;
+ } else {
+ image += static_cast(
+ (height - 1 - (line_no + static_cast(v)))) *
+ static_cast(x_stride) +
+ u;
+ }
+ *image = val;
+ }
+ }
+ } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
+ assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
+ for (size_t v = 0; v < static_cast(num_lines); v++) {
+ const float *line_ptr = reinterpret_cast(&outBuf.at(
+ v * pixel_data_size * static_cast(x_stride) +
+ channel_offset_list[c] * static_cast(x_stride)));
+ for (size_t u = 0; u < static_cast(width); u++) {
+ float val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
+
+ tinyexr::swap4(reinterpret_cast(&val));
+
+ float *image = reinterpret_cast(out_images)[c];
+ if (line_order == 0) {
+ image += (static_cast(line_no) + v) *
+ static_cast(x_stride) +
+ u;
+ } else {
+ image += static_cast(
+ (height - 1 - (line_no + static_cast(v)))) *
+ static_cast(x_stride) +
+ u;
+ }
+ *image = val;
+ }
+ }
+ } else {
+ assert(0);
+ }
+ }
+#else
+ assert(0 && "PIZ is enabled in this build");
+ return false;
+#endif
+
+ } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS ||
+ compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
+ // Allocate original data size.
+ std::vector outBuf(static_cast(width) *
+ static_cast(num_lines) *
+ pixel_data_size);
+
+ unsigned long dstLen = static_cast