diff --git a/.gitignore b/.gitignore index 5598044f1..60b6e53d5 100644 --- a/.gitignore +++ b/.gitignore @@ -222,6 +222,13 @@ $RECYCLE.BIN/ # Files created by make in various subdirectories .dirstamp +# =========================== +# POV-Ray meta-build detritus +# =========================== + +# Byte-compiled python modules +*.pyc + # ===================== # POV-Ray Miscellaneous # ===================== diff --git a/changes.txt b/changes.txt index dcf28c518..0fb73a930 100644 --- a/changes.txt +++ b/changes.txt @@ -69,6 +69,14 @@ Changed Behaviour - The `defined()` pseudo-function now returns `true` (while printing a warning) if applied to reserved words. The `#ifdef` and `#ifndef` directives also behave accordingly. + - The dithering implementation has been modified, and may produce slightly + different results for otherwise identical scenes. + - The PGM (greyscale variant of PPM) output gamma handling now matches that + of regular PPM, honoring `File_Gamma` defaulting to ITU-R BT.709. To get + linear greyscale output, explicitly specify `File_Gamma=1.0`. + - Greyscale output no longer automatically forces bit depth to 16 bpc. To get + 16 bpp greyscale output, explicitly specify `Bits_Per_Color=16`. + - Preview now reflects greyscale setting. New Features ------------ @@ -86,6 +94,13 @@ New Features the list of control points. - The `matrix` syntax now allows allows for a trailing comma at the end of the list of coefficients. + - File formats supporting variable bit depths (PNG and PPM/PGM) now allow for + bit depths as low as 1 bit per colour channel. (1-bit greyscale PPM/PGM will + still be written as PGM, not PBM.) + - Command-line option `+F` now allows specifying both the `G` greyscale flag + and the bit depth. + - Support for blue noise dithering has been added, plus a couple more error + diffusion dithering filters. Performance Improvements ------------------------ diff --git a/distribution/platform-specific/windows/Help/povray.chm b/distribution/platform-specific/windows/Help/povray.chm index 6056d9f78..9db9f8318 100644 Binary files a/distribution/platform-specific/windows/Help/povray.chm and b/distribution/platform-specific/windows/Help/povray.chm differ diff --git a/distribution/scenes/output/dither_showcase.pov b/distribution/scenes/output/dither_showcase.pov new file mode 100644 index 000000000..33b767129 --- /dev/null +++ b/distribution/scenes/output/dither_showcase.pov @@ -0,0 +1,118 @@ +// POV-Ray 3.8 Scene File "dither_showcase.pov" +// author: Christoph Lipka +// date: 2018-09-30 +// +//-------------------------------------------------------------------------- +#version 3.8; + +#ifndef (Glow) + #declare Glow = on; +#end +#ifndef (Brightness) + #declare Brightness = 4.0; +#end + +global_settings { + max_trace_level 5 + assumed_gamma 1.0 + radiosity { + pretrace_start 0.08 + pretrace_end 0.01 + count 150 + nearest_count 20 + error_bound 0.5 + recursion_limit 2 + low_error_factor .5 + gray_threshold 0.0 + minimum_reuse 0.015 + brightness 1 + adc_bailout 0.01/2 + } +} + +#default { + texture { + pigment {rgb 1} + finish { + ambient 0.0 + diffuse 0.8 + specular albedo 1.0 roughness 0.001 + reflection { 1.0 fresnel on } + conserve_energy + fresnel on + } + } +} + +// ---------------------------------------- + +#local TestRed = <1.0,.03,.03>; +#local TestGreen = <.03,1.0,.03>; +#local TestBlue = <.03,.03,1.0>; + +#local CameraFocus = <0,1,1>; +#local CameraDist = 8; +#local CameraDepth = 3.0; +#local CameraTilt = 5; + +camera { + location <0,0,0> + direction z*CameraDepth + right x*image_width/image_height + up y + translate <0,0,-CameraDist> + rotate x*CameraTilt + translate CameraFocus +} + +#macro LightSource(Pos,Color) + light_source { + Pos + color Color + area_light x*vlength(Pos)/10, y*vlength(Pos)/10, 9,9 adaptive 1 jitter circular orient + } + +#end + +LightSource(<-500,500,-500>, rgb Brightness) + +// ---------------------------------------- + +plane { + y, 0 + texture { pigment { color rgb 0.2 } } + interior { ior 1.5 } +} + +#macro TestSphere(Pos,Radius,TargetColor,Hole) + #if (Hole) + union { + #local Th = 20; + #local R = 0.05; + #local SinTh = sin(Th*pi/180); + #local CosTh = cos(Th*pi/180); + difference { + sphere { <0,0,0>, 1 } + cylinder { y, y*(1-R)*CosTh, SinTh } + cylinder {-y,-y*(1-R)*CosTh, SinTh } + cylinder { y,-y,(1-R)*SinTh-R } + } + torus { (1-R)*SinTh, R translate y*(1-R)*CosTh } + torus { (1-R)*SinTh, R translate -y*(1-R)*CosTh } + #else + sphere { <0,0,0>, 1 + #end + texture { pigment { color TargetColor } + finish { emission Glow * Brightness * 0.5 } + } + interior { ior 1.5 } + rotate z*30 + rotate y*clock*360 - y*45 + scale Radius + translate Pos + y*Radius + } +#end + +TestSphere(<-2,0,1>, 1, TestRed, false) +TestSphere(< 0,0,1>, 1, TestBlue, true) +TestSphere(< 2,0,1>, 1, TestGreen, false) diff --git a/distribution/scenes/gamma/gamma_showcase.pov b/distribution/scenes/output/gamma_showcase.pov similarity index 100% rename from distribution/scenes/gamma/gamma_showcase.pov rename to distribution/scenes/output/gamma_showcase.pov diff --git a/distribution/scenes/previews/gamma/gamma_showcase.jpg b/distribution/scenes/previews/output/gamma_showcase.jpg similarity index 100% rename from distribution/scenes/previews/gamma/gamma_showcase.jpg rename to distribution/scenes/previews/output/gamma_showcase.jpg diff --git a/doc/html/r3_0.html b/doc/html/r3_0.html index 3b0a14a4d..60d275290 100644 --- a/doc/html/r3_0.html +++ b/doc/html/r3_0.html @@ -289,19 +289,37 @@
BSP Bounding
-
Anti-Aliasing Options
+
Stochastic Seed
-
Radiosity Options
+
Anti-Aliasing Options
-
Radiosity High Reproducibility
+
Sampling Methods Synopsis
-
Radiosity Load and Save
+
Sampling Method 1
-
Radiosity Vain Pretrace
+
Sampling Method 2
+ + +
Sampling Method 3
+ + +
Common Properties
+ + +
Radiosity Options
+ + +
Radiosity High Reproducibility
+ + +
Radiosity Load and Save
+ + +
Radiosity Vain Pretrace
Scene Description Language
diff --git a/doc/html/r3_2.html b/doc/html/r3_2.html index 7cf78d275..8c2bc8372 100644 --- a/doc/html/r3_2.html +++ b/doc/html/r3_2.html @@ -174,19 +174,37 @@
BSP Bounding
-
Anti-Aliasing Options
+
Stochastic Seed
-
Radiosity Options
+
Anti-Aliasing Options
-
Radiosity High Reproducibility
+
Sampling Methods Synopsis
-
Radiosity Load and Save
+
Sampling Method 1
-
Radiosity Vain Pretrace
+
Sampling Method 2
+ + +
Sampling Method 3
+ + +
Common Properties
+ + +
Radiosity Options
+ + +
Radiosity High Reproducibility
+ + +
Radiosity Load and Save
+ + +
Radiosity Vain Pretrace
 
@@ -1282,6 +1300,8 @@

3.2.4 File Output Options

3.2.4.1 Output File Type

+

There has been a Change as of version 3.7 regarding the default output file type. For all supported platforms the default is now PNG.

+ @@ -1298,6 +1318,26 @@

3.2.4.1 Output File Type

+ + + + + + + + + + + + + + + + + + + + @@ -1315,7 +1355,7 @@

3.2.4.1 Output File Type

- + @@ -1324,125 +1364,105 @@

3.2.4.1 Output File Type

Output_File_Type=x Sets file output off; but in future use format x, depth n
Grayscale_Output=boolSets grayscale output on/off (PNG and PPM only)
Greyscale_Output=boolSame as Grayscale_Output=bool
+FxgnSets file output on; sets format x, sets grayscale if applicable, depth n
-FxgnSets file output off; but in future use format x, sets grayscale if applicable, depth n
Output_Alpha=bool Sets alpha output on/off
Bits_Per_Color=nSets file output bits/color to nSets file output bits/color to n. A Change in version 3.8 allows values ranging from 1 to 16.
-

Note: As of version 3.7 the default output file type for all supported platforms is PNG. You may select one of several different file types by using Output_File_Type=x or +Fx where x is one of the following:

+

You may select one of several different file types by using Output_File_Type=x or +Fx where x is one of the following:

- + - + - + - + - + - - + + - - + + - - + + - - + +
.. BB or b Universal Bitmap image file format
.. CC or c Compressed Targa-24 format (RLE, run length encoded)
.. EE or e OpenEXR High Dynamic-Range format
.. HH or h Radiance High Dynamic-Range format
.. JJ or j JPEG format (Note: This format is not loss-free and will generate compression artifacts)
.. NPNG (portable network graphics) formatN or nPNG (portable network graphics) format
.. PUnix PPM formatP or pUnix PPM format
.. SSystem-specific format: See the notation at the end of this section.S or sSystem-specific format: See the notation at the end of this section.
.. TUncompressed Targa-24 formatT or tUncompressed Targa-24 format
-

-New as of version 3.8, instead of Output_File_Type=C you can also use Output_File_Type=T Compression=1 to choose RLE-encoded Targa format. -

-

-PNG is an image format designed not only to replace GIF, but to improve on its shortcomings. PNG offers the highest compression available without loss for high quality applications, such as ray-tracing. -

-

-New Prior to version 3.8, PPM output always created the compact raw (binary) format. The Compression=0 ini setting can now be used to select the plain (ASCII) format instead. -

-

-The system specific format depends on the platform used and is covered in the appropriate system specific documentation. -

-

-JPEG is particularly good at achieving high compression rates with photographic or photorealistic images, making it one of the most frequently used formats on the Internet. However, it is not loss-free. Images generated with this option will always contain compression artifacts (image defects). If you need to keep a high-quality image you should render using one of the loss-free formats. -

+ +

Grayscale output can be used to generate heightfields for use in other POV-Ray scenes, by using Grayscale_Output=true as an INI option, or +Fxg for output type x as a command-line option. For example, +Fng for PNG and +Fpg for PPM (technically PGM) grayscale output. By default this option is off.

+ +

With Grayscale_Output=true, the output file will be in the form of a grayscale image that can be used to generate heightfields, as the height at any point is dependent on the brightness of the pixel. The brightness of a pixel is calculated in the same way that color images are converted to grayscale images: height = 0.3 * red + 0.59 * green + 0.11 * blue.

+ +

Previously, the grayscale PPM (technically PGM) output file format always used linear output. A Change in v3.8 will match that of the regular non-grayscale PPM format. That is File_Gamma will be honored if specified, otherwise the ITU-R BT.709 gamma transfer function will be applied.

+ +

In previous versions PPM output always created the compact raw (binary) format. A Change in version 3.8 now allows the use of INI setting Compression=0 to select the plain (ASCII) format instead. The system specific format depends on the platform used and is covered in the appropriate system specific documentation.

+ +

See also: Height Field for a description of how POV-Ray heightfields are stored for each file type.

+ +

Previously, specifying a bit-depth for grayscale file output was simply ignored and the bit-depth was forced to 16 bits per channel. A Change in version 3.8 now allows for a bit-depth setting.

+ +

It should also be noted that with previous versions setting the Grayscale_Output=true INI option would not cause the preview display, if used, to be grayscale. A Change in version 3.8 now shows a grayscale image on the preview display as well.

+ +

Currently PNG, and PPM are the only file formats that support grayscale output.

+ +

Last but not least, when choosing output file options it may be helpful to consider the following:

+ +

PNG is an image format designed not only to replace GIF, but to improve on its shortcomings. PNG offers the highest compression available without loss for high quality applications, such as ray-tracing. In addition to support for variable bit-depths, alpha channel, and grayscale formats, PNG files also store the File_Gamma value so the image displays properly on all systems.

+ +

JPEG is particularly good at achieving high compression rates with photographic or photorealistic images, making it one of the most frequently used formats on the Internet. However, it is not loss-free. Images generated with this option will always contain compression artifacts (image defects). If you need to keep a high-quality image you should render using one of the loss-free formats.

+

Note: Chroma sub-sampling has been disabled in JPEG output, and there has been a reduction in the default quality setting.

-

-The JPEG compression quality can be controlled using the Compression ini file option which, if set, needs to be an integer between 0 and 100. If values of 0 or 1 are specified then the default compression quality setting of 85% is used. Otherwise the value specified (2-100) is used as the compression quality setting. A value of 2 produces the smallest file (maximum compression), but looks terrible. A value of 100 produces the largest file (least compression) but can still contain some compression artifacts. Values lower than 0 are clipped to 0. Values greater than 100 are clipped to 100. -

-

-Most of these formats output 24 bits per pixel with 8 bits for each of red, -green and blue data. PNG and PPM allow you to optionally specify the output bit -depth from 5 to 16 bits for each of the red, green, and blue colors, giving -from 15 to 48 bits of color information per pixel. The default output depth -for all formats is 8 bits/color (16 million possible colors), but this may be -changed for PNG and PPM format files by setting Bits_Per_Color=n -or by specifying +FNn or +FPn, -where n is the desired bit depth.

-

-Specifying a smaller color depth like 5 bits/color (32768 colors) may be -enough for people with 8- or 16-bit (256 or 65536 color) displays, and will -improve compression of the PNG file. Higher bit depths like 10 or 12 may be -useful for video or publishing applications, and 16 bits/color is good for -grayscale height field output (See section Height Field for -details on height fields).

-

-Targa format also allows 8 bits of alpha transparency data to be output, -while PNG format allows 5 to 16 bits of alpha transparency data, depending on -the color bit depth as specified above. You may turn this option on with - Output_Alpha=on or +UA. The default is off or - -UA.

-

The alpha channel stores a transparency value for each pixel, just like -there is also stored a value for red green and blue light for each pixel. In -POV-Ray, when the alpha channel is turned on, all areas of the image -where the background is partly or fully visible will be partly or fully -transparent. Refractions of the background will also be transparent, but not -reflections. Also anti-aliasing is taken into account

-

The philosophy of the alpha channel feature in POV-Ray is that the -background color should not be present in the color of the image when the -alpha channel is used. Instead, the amount of visible background is kept in -the alpha and *only* in the alpha channel. That ensures that images look -correct when viewed with the alpha channel.

-

See section Using the Alpha Channel for -further details on using transparency in imagemaps in your scene.

+ +

The JPEG compression quality can be controlled using the Compression ini file option which, if set, needs to be an integer between 0 and 100. If values of 0 or 1 are specified then the default compression quality setting of 85% is used. Otherwise the value specified (2-100) is used as the compression quality setting. A value of 2 produces the smallest file (maximum compression), but looks terrible. A value of 100 produces the largest file (least compression) but can still contain some compression artifacts. Values lower than 0 are clipped to 0. Values greater than 100 are clipped to 100.

+ +

Most of these formats output 24 bits per pixel with 8 bits for each of red, green and blue data. PNG and PPM allow you to optionally specify the output bit depth from 1 to 16 bits for each of the red, green, and blue colors, giving from 15 to 48 bits of color information per pixel. The default output depth for all formats is 8 bits/color (16 million possible colors), but this may be changed for PNG and PPM format files by setting Bits_Per_Color=n or by specifying +FNn or +FPn, where n is the desired bit depth.

+ +

Specifying a smaller color depth like 5 bits/color (32768 colors) may be enough for people with 8- or 16-bit (256 or 65536 color) displays, and will improve compression of the PNG file. Higher bit depths like 10 or 12 may be useful for video or publishing applications, and 16 bits/color is good for grayscale height field output (See section Height Field for details on height fields).

+ +

Targa format also allows 8 bits of alpha transparency data to be output, while PNG format allows 5 to 16 bits of alpha transparency data, depending on the color bit depth as specified above. You may turn this option on with Output_Alpha=on or +UA. The default is off or -UA. New as of version 3.8, instead of Output_File_Type=C you can also use Output_File_Type=T Compression=1 to choose RLE-encoded Targa format.

+ +

The alpha channel stores a transparency value for each pixel, just like there is also stored a value for red green and blue light for each pixel. In POV-Ray, when the alpha channel is turned on, all areas of the image where the background is partly or fully visible will be partly or fully transparent. Refractions of the background will also be transparent, but not reflections. Also anti-aliasing is taken into account.

+ +

The philosophy of the alpha channel feature in POV-Ray is that the background color should not be present in the color of the image when the +alpha channel is used. Instead, the amount of visible background is kept in the alpha and *only* in the alpha channel. That ensures that images look correct when viewed with the alpha channel.

+ +

See section Using the Alpha Channel for further details on using transparency in imagemaps in your scene.

Note: In version 3.7 alpha handling for image file output has changed. Effectively, the background now requires a filter or transmit value in order for alpha transparency to work properly.

Previous versions of POV-Ray always wrote associated alpha for output, this has been changed on a per-file-format basis as follows:

-

-In addition to support for variable bit-depths, alpha channel, and grayscale -formats, PNG files also store the File_Gamma value so the -image displays properly on all systems. -The hf_gray_16 global setting, as described in section -HF_Gray_16 will also affect the -type of data written to the output file.

+

The Radiance Synthetic Imaging System or .hdr image format was originally developed to aid lighting designers and architects by predicting the light levels and appearance of a space prior to construction. The OpenEXR or .exr image file format was developed by Industrial Light & Magic™ for use in computer imaging applications.

+

Most image formats now include metadata (BMP is a notable exception). This metadata contains the POV-Ray version, render date/time (GMT), platform (e.g. x86_64-pc-win), and compiler used to build the POV-Ray executable.

Note: System-specific or type "s" output file format is being retained for legacy support reasons. Windows and Unix mapping remains the same, BMP and TGA respectively, however on Macintosh it has been changed to PNG, and a warning is issued when type "s" is used.

@@ -1523,15 +1543,34 @@

3.2.4.4 Output File Dithering

+

Ordered dithering algorithms:

+ + +

Error diffusion dithering algorithms:

-

The default is -THfs i.e: dithering is off, with Floyd-Steinberg being the default if only +TH is specified.

+

As always file output dithering is off by default, however a Change in version 3.8 now sets the default dithering method from FS to BN if only +TH is specified.

+ +

In version 3.7 the display preview window used Bayer 4x4 dithering. A Change in version 3.8 has switched that to the recently added blue noise pattern.

+

New in version 3.8 dithering is now fully supported for Radiance HDR output files.

+ +

New in version 3.8 file output dithering is now fully gamma-aware. The overall apparent brightness of the resulting image is faithfully reproduced.

+

Dithering works for all file formats except JPEG (where dithering would be counter-productive) and OpenEXR (which provides sufficient precision to make dithering obsolete). These file formats simply ignore the setting.

Note: While dithering does help to reduce color banding, it may instead lead to artifacts in prints, due to interference with the printing device's own dithering algorithms; in that case, choosing a different dither method may help.

@@ -1622,8 +1661,8 @@

3.2.5.1 Constant

radiosity { ... } -#end -} + #end + }
@@ -1698,24 +1737,7 @@

3.2.5.4 Language Version

-

As POV-Ray has evolved from version 1.0 through to today we have made every -effort to maintain some amount of backwards compatibility with earlier -versions. Some old or obsolete features can be handled directly without any -special consideration by the user. Some old or obsolete features can no -longer be handled at all. However some old features can still be -used if you warn POV-Ray that this is an older scene. In the POV-Ray scene -language you can use the #version directive to switch version -compatibility to different settings. See section The #version Directive -for more details about the language version directive. -Additionally you may use the Version=n.n option or the -+MVn.n switch to establish the initial -setting. For example one feature introduced in 2.0 that was incompatible with -any 1.0 scene files is the parsing of float expressions. Setting -Version=1.0 or using +MV1.0 turns off expression parsing -as well as many warning messages so that nearly all 1.0 files will still -work. Naturally the default setting for this option is the current version number.

- -

The version directive and command-line setting no longer provide compatibility with most rendering bugs in versions prior to POV-Ray 3.5. However, compatibility with the scene language is provided for scenes as old as POV-Ray 1.0 just as in all previous versions of POV-Ray. Nevertheless, we strongly recommend you update scenes at least to POV-Ray 3.5 syntax if you plan to use them in future versions of POV-Ray.

+

See also: Version Directive

@@ -3109,7 +3131,7 @@

3.2.8.6 BSP Bounding

BSP_IsectCost=150.0 BSP_MissChance=0.2 -

The values shown above are the default. You can also get the defaults if you use a value of 0 for any of the above, or of course just by not specifying the option at all. For an explanation of what the values mean you may refer to Ray Tracing News article by Eric Haines.

+

The values shown above are the default. You can also get the defaults if you use a value of 0 for any of the above, or of course just by not specifying the option at all. For an explanation of what the values mean you may refer to Ray Tracing News article by Eric Haines.

See the distribution file ~scenes/bsp/Tango.pov for a good example of a scene that benefits from the BSP bounding.

Tango.pov rendered at 800x600, no AA

-
-

3.2.8.7 Anti-Aliasing Options

+
+

3.2.8.7 Stochastic Seed

+ + + + + + + + + + +
Stochastic_Seed=nSets a value for the stochastic seed New in version 3.8
+SSnSame as Stochastic_Seed=n
+

By default some stochastic mechanisms in POV-Ray intentionally give different results for each render, with the intent that multiple renders can be averaged to get a higher-quality image. To this end, the corresponding pseudo-random number generators are seeded with a value +derived from the current date and time.

+

If the Stochastic_Seed=n or +SSn option is specified, the seed will instead be derived from the specified value, allowing to produce exactly the same output each time by specifying that same value. Alternatively, the mechanism may be co-opted to prevent separate renders started at the same time from producing identical results, by explicitly specifying different values.

+

Note: Even if the seed is set identically, other factors may cause differences in the result. For example the render block size +BSn or the render pattern +RPn options. Results may also differ between versions of POV-Ray.

+

Presently anti-aliasing sampling method 3 is the only feature that is sensitive to the stochastic seed setting.

+ +
+ +
+

3.2.8.8 Anti-Aliasing Options

@@ -3139,8 +3182,7 @@

3.2.8.7 Anti-Aliasing Options

- + @@ -3194,6 +3236,16 @@

3.2.8.7 Anti-Aliasing Options

+ + + + + + + + + + @@ -3216,19 +3268,38 @@

3.2.8.7 Anti-Aliasing Options

Antialias=bool
Sampling_Method=nSets aa-sampling method (only 1 or 2 are -valid)Sets aa-sampling method (either 1, 2 or 3 the later is New in version 3.8 )
Sets aa-jitter off (jitter amount n.n in future)
Antialias_Confidence=n.nSets method 3 confidence to n.n New in version 3.8
+ACn.nSame as Antialias_Confidence=n.n New in version 3.8
Antialias_Depth=n Sets aa-depth (1 <= n <= 9)

The ray-tracing process is in effect a discrete, digital sampling of the image with typically one sample per pixel. Such sampling can introduce a variety of errors. This includes a jagged, stair-step appearance in sloping or curved lines, a broken look for thin lines, moiré patterns of interference and lost detail or missing objects, which are so small they reside between adjacent pixels. The effect that is responsible for those errors is called aliasing.

-

Anti-aliasing is any technique used to help eliminate such errors or to reduce the negative impact they have on the image. In general, anti-aliasing makes the ray-traced image look smoother. The Antialias=on option or +A switch turns on POV-Ray's anti-aliasing system.

+

Anti-aliasing is any technique used to help eliminate such errors or to reduce the negative impact they have on the image. In general, anti-aliasing makes the ray-traced image look smoother. The Antialias=on option or +A option turns on POV-Ray's anti-aliasing system.

When anti-aliasing is turned on, POV-Ray attempts to reduce the errors by shooting more than one viewing ray into each pixel and averaging the results to determine the pixel's apparent color. This technique is called super-sampling and can improve the appearance of the final image but it drastically increases the time required to render a scene since many more calculations have to be done.

-

POV-Ray gives you the option to use one of two alternate super-sampling methods. The Sampling_Method=n option or +AMn switch selects either type 1 or type 2. Selecting one of those methods does not turn anti-aliasing on. This has to be done by using the +A command line switch or Antialias=on option.

-

Type 1 is an adaptive, non-recursive, super-sampling method. It is adaptive because not every pixel is super-sampled. Type 2 is an adaptive and recursive super-sampling method. It is recursive because the pixel is sub-divided and sub-sub-divided recursively. The adaptive nature of type 2 is the variable depth of recursion.

-

In the default, non-recursive method (+AM1), POV-Ray initially traces one ray per pixel. If the color of a pixel differs from its neighbors (to the left or above) by at least the set threshold value then the pixel is super-sampled by shooting a given, fixed number of additional rays. The default threshold is 0.3 but it may be changed using the Antialias_Threshold=n.n option. When the switches are used, the threshold may optionally follow the +A. For example +A0.1 turns anti-aliasing on and sets the threshold to 0.1.

+

POV-Ray gives you the option to use one of three sampling methods. Two alternate super-sampling methods and one over-sampling method. The Sampling_Method=n option or +AMn option selects either type 1, type 2 or type 3. Selecting one of those methods does not turn on anti-aliasing. This has to be done by using the +A command line option or Antialias=on option.

+ +
+ +
+
3.2.8.8.1 Sampling Methods Synopsis
+ + +
+ +
+
3.2.8.8.2 Sampling Method 1
+

+AM1 is an adaptive non-recursive method. If anti-aliasing is enabled it is the default. POV-Ray initially traces one ray per pixel. If the color of a pixel differs from its neighbors (to the left or above) by at least the set threshold value then the pixel is super-sampled by shooting a given, fixed number of additional rays. The default threshold is 0.3 but it may be changed using the Antialias_Threshold=n.n option. When the switches are used, the threshold may optionally follow the +A. For example +A0.1 turns anti-aliasing on and sets the threshold to 0.1.

The threshold comparison is computed as follows. If r1, g1, b1 and r2, g2, b2 are the rgb components of two pixels then the difference between pixels is computed by

 diff = abs(r1-r2) + abs(g1-g2) + abs(b1-b2)
 

If this difference is greater than the threshold then both pixels are super-sampled. The rgb values are in the range from 0.0 to 1.0 thus the most two pixels can differ is 3.0. If the anti-aliasing threshold is 0.0 then every pixel is super-sampled. If the threshold is 3.0 then no anti-aliasing is done. Lower threshold means more anti-aliasing and less speed. Use anti-aliasing for your final version of a picture, not the rough draft. The lower the contrast, the lower the threshold should be. Higher contrast pictures can get away with higher tolerance values. Good values seem to be around 0.2 to 0.4.

When using the non-recursive method, the default number of super-samples is nine per pixel, located on a 3*3 grid. The -Antialias_Depth=n option or +Rn switch controls the number of rows and columns of samples taken for a super-sampled pixel. For example +R4 would give 4*4=16 samples per pixel.

-

The second, adaptive, recursive super-sampling method starts by tracing four rays at the corners of each pixel. If the resulting colors differ more than the threshold amount additional samples will be taken. This is done recursively, i.e. the pixel is divided into four sub-pixels that are separately traced and tested for further subdivision. The advantage of this method is the reduced number of rays that have to be traced. Samples that are common among adjacent pixels and sub-pixels are stored and reused to avoid re-tracing of rays. The recursive character of this method makes the super-sampling concentrate on those parts of the pixel that are more likely to need super-sampling (see figure below).

+Antialias_Depth=n option or +Rn option controls the number of rows and columns of samples taken for a super-sampled pixel. For example +R4 would give 4*4=16 samples per pixel.

+ +
+ +
+
3.2.8.8.3 Sampling Method 2
+

+AM2 is an adaptive, recursive super-sampling method. It starts by tracing four rays at the corners of each pixel. If the resulting colors differ more than the threshold amount additional samples will be taken. This is done recursively, i.e. the pixel is divided into four sub-pixels that are separately traced and tested for further subdivision. The advantage of this method is the reduced number of rays that have to be traced. Samples that are common among adjacent pixels and sub-pixels are stored and reused to avoid re-tracing of rays. The recursive character of this method makes the super-sampling concentrate on those parts of the pixel that are more likely to need super-sampling (see figure below).

@@ -3241,7 +3312,7 @@

3.2.8.7 Anti-Aliasing Options

-

The maximum number of subdivisions is specified by the Antialias_Depth=n option or +Rn switch. This is different from the adaptive, non-recursive method where the total number of super-samples is specified. A maximum number of n subdivisions results in a maximum number of samples per pixel that is given by the following table. Where the first column represents anti-alias depth or +Rn option. The second column is the number of additional samples per super-sampled pixel for the non-recursive method +AM1. Lastly the third column is the maximum number of samples per super-sampled pixel for the recursive method +AM2.

+

The maximum number of subdivisions is specified by the Antialias_Depth=n option or +Rn option. This is different from the adaptive, non-recursive method where the total number of super-samples is specified. A maximum number of n subdivisions results in a maximum number of samples per pixel that is given by the following table. Where the first column represents anti-alias depth or +Rn option. The second column is the number of additional samples per super-sampled pixel for the non-recursive method +AM1. Lastly the third column is the maximum number of samples per super-sampled pixel for the recursive method +AM2.

@@ -3299,28 +3370,50 @@

3.2.8.7 Anti-Aliasing Options

-

Note: The maximum number of samples in the recursive case is hardly ever reached for a given pixel. If the recursive method is used with no anti-aliasing each pixel will be the average of the rays traced at its corners. In most cases a recursion level of three is sufficient.

-

Another way to reduce aliasing artifacts is to introduce noise into the sampling process. This is called jittering and works because the human visual system is much more forgiving to noise than it is to regular patterns. The location of the super-samples is jittered or wiggled a tiny amount when anti-aliasing is used. Jittering is used by default but it may be turned off with the Jitter=off option or -J switch. The amount of jittering can be set with the Jitter_Amount=n.n option. When using switches the jitter scale may be specified after the +Jn.n switch. For example +J0.5 uses half the normal jitter. The default amount of 1.0 is the maximum jitter which will insure that all super-samples remain inside the original pixel.

+

Note: The maximum number of samples in the recursive case is hardly ever reached for a given pixel. If the recursive method is used and the anti-aliasing threshold is not reached, each pixel will be the average of the rays traced at its corners. In others words, you get the average of those four pixels with no further sub-sampling. In most cases a recursion level of three is sufficient.

+ +
+ +
+
3.2.8.8.4 Sampling Method 3
+

+AM3 is New in version 3.8 and it's an adaptive, non-recursive stochastic oversampling method. This method repeatedly iterates over the pixels to be rendered, jittering each ray randomly within the pixel on each pass, while keeping track of statistical parameters such as average color and mean deviation. On subsequent passes, the algorithm ceases to over-sample pixels where the +statistical parameters for the pixel itself and its immediate four neighbors indicate that the result is probably good enough.

+

What constitutes probably good enough is determined by a confidence parameter specified by the Antialias_Confidence=n.n or +ACn.n option, as well as a threshold parameter specified by the Antialias_Threshold=n.n or +An.n option.

+

The threshold determines what absolute sampling error (i.e. difference between the computed pixel color and the theoretically correct one) you consider acceptable, while the confidence specifies how sure you want to be that a pixel that seems acceptable actually is acceptable. In effect, this determines how many pixels in the resulting image will indeed be acceptable. For example, if you specify a confidence of 0.95, then you can expect approximately 95% of all pixels to be within the threshold, as compared to a theoretically correct image. Of the remaining ones, many will be off by slightly more than the threshold, while only few will be significantly off. Extreme outlines are possible but extremely unlikely.

+

Recommended values are a threshold of 0.3 or lower, and a confidence of 0.9 or higher. They are the defaults.

+

The total number of rays shot per pixel is limited by the Antialias_Depth=n or +Rn parameter. As with the other methods the parameter is limited to the range from 1 to 9, with the actual maximum number of rays per pixel being 4n.

+

By default, the sub-pixel jittering is different for each render, thus giving slightly different results, with the intent that multiple renders can be averaged to get a higher-quality image. Conversely you can produce exactly the same output each time. See also: Stochastic Seed

+

Note: The jitter sequence is also affected by the actual image content, and will thus always differ between the frames of an animation.

+

Since oversampling method 3 is a very generic adaptive oversampling algorithm, its performance in pure edge anti-aliasing is generally inferior to the other methods, however it is ideally suited to suppress random image noise created by other stochastic mechanisms, such as +jittered area lights, subsurface light transport, or micro-normals based blurred reflections. It has also proven well-suited for eliminating moiré patterns.

+ +
+ +
+
3.2.8.8.5 Common Properties
+

Another way to reduce anti-aliasing artifacts is to introduce noise into the sampling process. This is called jittering and works because the human visual system is much more forgiving to noise than it is to regular patterns. It is inherent to anti-aliasing method 3 because it always uses a constant amount of jitter. When using one of the other methods the location of the super-samples is also jittered or wiggled a tiny amount by default. Alternately it may be turned off with the Jitter=off option or -J option. The amount of jittering can be set with the Jitter_Amount=n.n option. When using those options the jitter scale may be specified after the +Jn.n option. For example +J0.5 uses half the normal jitter. The default amount of 1.0 is the maximum jitter which will insure that all super-samples remain inside the original pixel.

Note: The jittering noise is random and non-repeatable so you should avoid using jitter in animation sequences as the anti-aliased pixels will vary and flicker annoyingly from frame to frame.

If anti-aliasing is not used one sample per pixel is taken regardless of the super-sampling method specified.

-

As the human eye is more sensitive to absolute brightness differences at a low overall brigtness than at higher ones, super-sampling based on linear light intensity differences would yield either poor anti-aliasing in darker regions, or unnecessary super-sampling in brighter regions of the image. To avoid this, POV-Ray compares ''gamma-adjusted'' values instead. (Note that this only affects the comparison operation; the averaging of the super-samples is done in whatever working color space is specified in the scene file via the assumed_gamma keyword.) The Antialias_Gamma=n.n command line option or +AGn.n sets the gamma to apply before comparison, defaulting to 2.5. Note that the value is actually the inverse of the gamma applied, in order to use the same value range as the display and file gamma settings. Neutral behavior can be achieved using Antialias_Gamma=1.0

+

As the human eye is more sensitive to absolute brightness differences at a low overall brigtness than at higher ones, super-sampling based on linear light intensity differences would yield either poor anti-aliasing in darker regions, or unnecessary super-sampling in brighter regions of the image. To avoid this, POV-Ray compares gamma-adjusted values instead.

+

Note: This only affects the comparison operation. The averaging of the super-samples is done in whatever working color space is specified in the scene file via the assumed_gamma keyword.

+

The Antialias_Gamma=n.n command line option or +AGn.n sets the gamma to apply before comparison. The default is 2.5. This value is actually the inverse of the gamma applied, in order to use the same value range as the display and file gamma settings. If the image contains an alpha channel, that channel will also be considered in the comparisons, like the color channels, except that unlike the other channels it is not subject to Antialias_Gamma. Neutral behavior can be achieved using Antialias_Gamma=1.0

Note: The mesh_camera feature added in version 3.7 also makes extreme super-sampling possible. See the distribution file ~scenes/camera/mesh_camera/ess/README.txt for additional information.

- -
-

3.2.8.8 Radiosity Options

+ +
+

3.2.8.9 Radiosity Options

- -
-
3.2.8.8.1 Radiosity High Reproducibility
+ +
+
3.2.8.9.1 Radiosity High Reproducibility

As of version 3.7 a new radiosity mode has been introduced. When specifying High_Reproducibility or +HR on the command line, POV-Ray will spend extra effort to make sure renders are deterministic despite SMP. Currently radiosity is the only code to use this flag; in +HR mode, radiosity pretrace starts out with fewer threads, and some extra rules are imposed on sample re-use that may cause surplus samples to be gathered.

Note: The high reproducibility mode is not intended for use with radiosity alone, and it will need more work to guarantee the same improved reproducibility in other features. Even though it works well with radiosity, this addition is still experimental.

- -
-
3.2.8.8.2 Radiosity Load and Save
+ +
+
3.2.8.9.2 Radiosity Load and Save

The following .ini / command line parameters are recognized:

 Radiosity_File_Name="<name>"	or +RF"<name>"	to set the cache file name
@@ -3332,9 +3425,9 @@ 
3.2.8.8.2 Radiosity Load and Save

New samples gathered are written whenever an SMP block is completed. Tests indicate that this is almost neutral regarding performance, compared to operation with radiosity file output disabled.

- -
-
3.2.8.8.3 Radiosity Vain Pretrace
+ +
+
3.2.8.9.3 Radiosity Vain Pretrace

Also new as of version 3.7 an option has been added to speed up radiosity pretrace:

As some computations don't contribute to the generation of radiosity samples, they can safely be skipped during radiosity pretrace to gain some speed if the pretrace's other role as a coarse preview is not required.

The following .ini file/command line options control whether pretrace performs all computations so it can double-feature as a coarse preview (vain pretrace):

diff --git a/doc/html/r3_3.html b/doc/html/r3_3.html index a9dc30a86..1f4d87dd8 100644 --- a/doc/html/r3_3.html +++ b/doc/html/r3_3.html @@ -872,6 +872,7 @@

3.3.1.2 Keywords

min
min_extent
minimum_reuse
+mixed
mm_per_unit
mod
mortar
@@ -3059,9 +3060,9 @@
3.3.1.8.3 Declaring User-Defined Float Functions
3.3.1.8.4 Declaring User-Defined Vector Functions
-

Right now you may only declare vector functions using one of the special -function types. Supported types are transform and -spline functions. For example:

+

Right now you may only declare vector functions using one of the special function types. Supported types are transform and +spline functions.

+

For example:

 #declare foo = function {
@@ -3084,13 +3085,9 @@ 
3.3.1.8.4 Declaring User-Defined Vector Functions
#declare myvector2 = foo2(0.7);
-

Function splines take the vector size into account. That is, a function -containing a spline with five components will also return a five component -vector (aka a color), a function containing a spline with two components will -only return a two component vector and so on.

+

Function transforms return a three component vector, while function splines take the vector size into account. That is, a function containing a spline with five components will also return a five component vector (aka a color), a function containing a spline with two components will only return a two component vector and so on.

-

Note: The number of parameters of special -function types is determined automatically, so you do not need to specify +

Note: The number of parameters of special function types is determined automatically, so you do not need to specify parameter names.

@@ -3460,7 +3457,7 @@
3.3.1.9.5 Built-in Variables

3.3.1.10 Array

-

You may declare arrays of identifiers with up to five dimensions. Any item that can be declared as an identifier can be declared in an array. Consequential to the improvements with the classic array container topology, a New feature in version 3.8 extended functionality to allow the creation of dictionary container types. Dictionaries can be used for mapping string keys to arbitrary-type values.

+

You may declare arrays of identifiers with up to five dimensions. Any item that can be declared as an identifier can be declared in an array. Consequential to the improvements with the classic array container topology, two New features in version 3.8 extended functionality to allow the creation of dictionary container types. Additionally arrays now support a mixed-type declaration. Dictionaries can be used for mapping string keys to arbitrary-type values. The mixed-type declaration allows the array to hold elements of different types.

@@ -3470,8 +3467,8 @@
3.3.1.10.1 Declaring Arrays
 ARRAY_DECLARATION:
-  #declare IDENTIFIER = array[ INT ][[ INT ]]..[ARRAY_INITIALIZER] |
-  #local IDENTIFIER = array[ INT ][[ INT ]]..[ARRAY_INITIALIZER]
+  #declare IDENTIFIER = array [mixed] [[ INT ]]..[ARRAY_INITIALIZER] |
+  #local IDENTIFIER = array [mixed] [[ INT ]]..[ARRAY_INITIALIZER]
 ARRAY_INITIALIZER:
   {ARRAY_ITEM, [ARRAY_ITEM, ]... }
 ARRAY_ITEM:
@@ -3483,7 +3480,7 @@ 
3.3.1.10.1 Declaring Arrays
DICTIONARY_INITIALIZER: {DICTIONARY_ITEM, [DICTIONARY_ITEM, ]... } DICTIONARY_ITEM: - ["STRING"]: DICTIONARY_ENTRY | .STRING_IDENTIFIER: DICTIONARY_ENTRY + [ STRING ] : DICTIONARY_ENTRY | .STRING_IDENTIFIER: DICTIONARY_ENTRY DICTIONARY_ENTRY: Any valid array entry
@@ -3500,7 +3497,7 @@
3.3.1.10.1 Declaring Arrays
#declare MyArray = array[10] -

It declares an uninitialized array of ten elements. The elements are referenced as MyArray[0] through MyArray[9]. As yet, the type of the elements are undetermined. Once you have initialized any element of the array, all other elements can only be defined as that type. Any attempt to reference an uninitialized element results in an error. More below:

+

It declares an uninitialized array of ten elements. The elements are referenced as MyArray[0] through MyArray[9]. As yet, the type of the elements are undetermined. Once you have initialized any element of the array, all other elements can only be defined as that type. New in version 3.8 this behavior can be over-ridden by using the mixed keyword in the array declaration allowing mixed-type elements. Irregardless of whether the array elements have mixed-types or not, any attempt to reference an uninitialized element results in an error. More below:

 #declare MyArray = array[10]
@@ -3588,6 +3585,13 @@ 
3.3.1.10.1 Declaring Arrays
// declare a local and un-define any global variable of same name #declare local.Foo = 4711; #undef global.Foo; + +// mixed-type array declaration +#declare Foo = array mixed[3]; +#declare Foo[0] = 42; +#declare Foo[1] = "Fnord"; +#declare Foo[2] = sphere { <0,0,0>, 1 } +
@@ -4418,18 +4422,28 @@

3.3.2.4 Default Directive

3.3.2.5 Version Directive

-

As POV-Ray has evolved from version 1.0 through 3.8 we have made every effort to maintain some amount of backwards compatibility with earlier versions. Some old or obsolete features can be handled directly without any special consideration by the user. Some old or obsolete features can no longer be handled at all. However some old features can still be -used if you warn POV-Ray that this is an older scene. The #version directive can be used to switch version compatibility to different setting several times throughout a scene file. The syntax is:

+

Since POV-Ray has evolved over the years from version 1.0 through 3.8 we have made every effort to maintain some amount of backwards compatibility with earlier versions. Some old or obsolete features can be handled directly without any special consideration by the user. Some old or obsolete features can no longer be handled at all. However some old features can still be used if you alert POV-Ray that this is an older scene. The #version directive can be used to switch version compatibility or change default settings several times throughout a scene file.

+ +

The syntax is:

+
 VERSION_DIRECTIVE: 
   #version FLOAT;
 
-

Note: There should be a semi-colon after the float expression in a #version directive. This semi-colon is introduced in POV-Ray version 3.1. If omitted, it generates a warning and some macros may not work -properly.

-

Additionally you may use the Version=n.n option or the +MVn.n switch to establish the initial setting. See Language Version for details. For example, one feature introduced in 2.0 that was incompatible with any 1.0 scene files is the parsing of float expressions. Using #version 1.0 turns off expression parsing as well as many warning messages so that nearly all 1.0 files will still work.

-

Note: Some obsolete or re-designed features are totally unavailable in the current version of POV-Ray REGARDLESS OF THE VERSION SETTING. Details on these features are noted throughout this documentation.

-

The built-in float identifier version contains the current setting of the version compatibility option. See -Float Expressions: Built-in Variables. Together with the built-in version identifier the #version directive allows you to save and restore the previous values of this compatibility setting. The new #local identifier option is especially useful here. For example, suppose mystuff.inc is in version 3.5 format. At the top of the file you could put:

+ +

There must be a semi-colon after the float expression in a #version directive. If omitted a warning is generated and some macros may not work properly. Additionally you may use the Version=n.n option or the +MVn.n switch to establish the initial setting. For example, the parsing of float expressions was introduced in version 2.0 and it was incompatible with any version 1.0 scene file. Using #version 1.0 turns off expression parsing as well as many warning messages so that nearly all 1.0 files will still work. Some obsolete or re-designed features are totally unavailable in the current version of POV-Ray REGARDLESS OF THE VERSION SETTING. Details on these features are noted throughout this documentation.

+ +

As of version 3.7 the following requirement has been implemented. In order to obtain full version 3.7 functionality you MUST specify the #version 3.7; directive in your scene file. Prior to a #version directive appearing the version defaults to 3.62. Additionally, if the first #version directive appears after any other declaration, or a #version directive does not appear at all a post-parse warning is issued. A Change as of POV-Ray 3.8 now makes it an outright error to use #version 3.8; or higher in a main scene file that does not start with a #version directive.

+ +

New defaults require that the language version is explicitly set to 3.8 or higher via the #version directive the Version=n.n INI setting or the +MVn.n command-line option. Otherwise POV-Ray will fall back to legacy defaults for backwards compatibility.

+ +

If you do need to do some processing before you decide on a version compatibility option start your scene with the following +construct:

+
+  #version version;
+
+ +

The built-in float identifier version contains the current setting of the version compatibility option. See Float Expressions: Built-in Variables. Together with the built-in version identifier and the #version directive will allow you to save and restore the previous values of this compatibility setting. The #local identifier option is especially useful here. For example the include file mystuff.inc is in version 3.5 format, so at the top of that file you would include:

   #local Temp_Vers = version;  // Save previous value
   #version 3.5;                // Change to 3.5 mode
@@ -4437,24 +4451,35 @@ 

3.3.2.5 Version Directive

#version Temp_Vers; // Restore previous version
-

As of version 3.7, there has been a requirement implemented. In order to obtain full version 3.7 -functionality, you MUST specify the #version 3.7 directive in your scene file. Prior to a -#version directive appearing, the version defaults to 3.62. Additionally, if the first #version -appears after any other declaration, or a #version directive does not appear at all, -a post-parse warning is issued, and a Change as of POV-Ray 3.8 or later it is now considered an outright error to use -#version 3.8 or higher in a main scene file that does not start with a #version directive.

+

Note: In version 3.7, if the version compatibility option was left at its default, the version identifier evaluated to the actual POV-Ray version number, instead of matching the defaulted version compatibility setting of 3.62. This would cause problems with include files using the above construct, as it would inadvertently switch the compatibility setting from 3.62 to 3.7. This has been fixed by a Change in version 3.8, where the version identifier matches the version compatibility option default in such a situation. There is still one exception to this rule: If the scene starts with a #version directive, and the version identifier is used in that directive, it will default to the actual POV-Ray version number in that very first statement, so that the #version version; idiom can still be used.

+ +

As previously mentioned the #version directive can be used to switch back and forth between the defaults as long as no explicit #default directive statement is specified. However, as soon as the first #default directive is encountered, any subsequent #version directives that would normally affect the defaults will instead just generate a warning.

+ +

Consider the following examples in their entirety:

-

If you do need to do some processing before you decide on a version compatibility option, start your scene with the following -construct:

-  #version version;
+  #version 3.7;
+  #declare LegacyTexture = texture { ... }
+
+ +

The #version directive switches to the version 3.7 defaults. If LegacyTexture does not explicitly specify an ambient value it will be set to a value of 0.1

+ +
+  #version 3.8;
+  #declare ModernTexture = texture { ... }
+  #default { pigment { color rgb <1,0,0> } }
+
+ +

The #version directive switches to the version 3.8 defaults. If ModernTexture does not explicitly specify an ambient value, it will be set to a value of zero.

+ +
+  #version 3.7;
+  #declare OtherTexture = texture { ... }
 
-Note that unless the version compatibility option has explicitly been set by the INI file option Version=n.n -or by the +MVn.n command-line switch, version evaluates to the actual POV-Ray software version -when used inside the first #version statement, even in version 3.8 or later where it evaluates to the effective -version compatibility option anywhere else. -

Warning: The version directive and command-line setting no longer provide compatibility with most rendering bugs in versions prior to POV-Ray 3.5. However, compatibility with the scene language is provided for scenes as old as POV-Ray 1.0 just as in all previous versions of POV-Ray. Nevertheless, we strongly recommend you update scenes at least to POV-Ray 3.5 syntax if you plan to use them in future versions of POV-Ray.

+

The #version directive just generates a warning because the earlier #default directive has locked the version 3.8 defaults overriding the pigment in the process. If OtherTexture does not explicitly specify an ambient value, it will also have an ambient value of zero.

+ +

Note: The version directive and command-line setting no longer provides compatibility with most rendering bugs in versions prior to POV-Ray 3.5. However, compatibility with the scene language is provided for scenes as old as POV-Ray 1.0 just as in all previous versions of POV-Ray. Nevertheless, we strongly recommend you update scenes at least to POV-Ray 3.7 syntax if you plan to use them in future versions of POV-Ray.

diff --git a/doc/html/r3_4.html b/doc/html/r3_4.html index 9c6a5076c..7c9bb0900 100644 --- a/doc/html/r3_4.html +++ b/doc/html/r3_4.html @@ -493,17 +493,7 @@

3.4.1.3 Assumed_Gamma

3.4.1.4 HF_Gray_16

-

Note: In version 3.7 the hf_gray_16 keyword in the global_settings block has been deprecated. If encountered, it has no effect on the output type and will additionally generate a warning message.

- -

However grayscale output can still be used to generate heightfields for use in other POV-Ray scenes, and now should be specified by using Grayscale_Output=true as an INI option, or +Fxg (for output type 'x') as a command-line option. For example, +Fng for PNG and +Fpg for PPM (effectively PGM) grayscale output. By default this option is off.

- -

With Grayscale_Output=true, the output file will be in the form of a grayscale image that can be used to generate heightfields, because the height at any point is dependent on the brightness of the pixel. The brightness of a pixel is calculated in the same way that color images are converted to grayscale images: height = 0.3 * red + 0.59 * green + 0.11 * blue.

- -

It should also be noted that setting the Grayscale_Output=true INI option will NOT cause the preview display, if used, to be grayscale rather than color. See the section Height Field for a description of how POV-Ray heightfields are stored for each file type.

- -

Note: Grayscale output implies the maximum bit-depth the format supports is 16, it is not valid to specify bits per color channel with 'g' (e.g. +Fng16 is not allowed, and nor for that matter is +Fn16g). If bits per channel is provided via an INI option, it is ignored.

- -

Currently PNG, and PPM are the only file formats that support grayscale output.

+

A Change as of version 3.7 has deprecated the hf_gray_16 keyword in the global_settings block. If encountered, it has no effect on the output type and will additionally generate a warning message. Grayscale output can still be used to generate heightfields for use in other POV-Ray scenes. See: Output File Type for details.

@@ -899,6 +889,7 @@
3.4.2.1.5 Up and Right Vectors
visible. All viewing rays are perpendicular to the y-axis. For type 2 and 4, the cylinder lies along the right vector. Viewing rays for type 4 are perpendicular to the right vector.

+

See Also: Aspect Ratio

Note: The up, right, and direction vectors should always remain perpendicular to each other or the image will be distorted. If this is not the case a warning message will be printed. The vista buffer will not work for non-perpendicular camera vectors.

@@ -907,7 +898,7 @@
3.4.2.1.5 Up and Right Vectors
3.4.2.1.6 Aspect Ratio

Together the right (width) and up (height) vectors define the aspect ratio of the resulting image.

-

A Change in version 3.8 redefines how the right vector default is derived. Previously a fixed value, it is now a calculated value that is based on the image width and height specified at render time. As usual, the image width and height can be specified from either the pull down menu available in GUI versions ONLY or the +Wn and +Hn command-line options available to ALL versions. This behavior is conditional upon the last effective #version directive before the camera definition. The default up vector remains as <0,1,0>.

+

A Change in version 3.8 redefines how the right vector default is derived. The default setting is now right <image_width/image_height,0,0> as opposed to the right <1.33,0,0> value used in previous versions. Requires #version 3.8; or equivalent INI setting or command-line option. See also: Version Directive. As usual, the image width and height can be specified from either the pull down menu available in GUI versions ONLY or the +Wn and +Hn command-line options available to ALL versions. The default up vector remains as <0,1,0>.

To retain legacy behavior see the example below:

@@ -2419,7 +2410,7 @@
3.4.3.3.3.13 recursion_limit
3.4.3.3.4 Configuring Radiosity
-

The following parameters deal with configuring radiosity and how it interacts with other features. See also these additional command line options for more control.

+

The following parameters deal with configuring radiosity and how it interacts with other features. See also these additional command line options for more control.

@@ -2459,7 +2450,7 @@
3.4.3.3.4.4 Normal and Radiosity
3.4.3.3.4.5 Save and Load Radiosity Data

In general, it is not a good idea to save and load radiosity data if scene objects are moving. Even after the data is loaded, more samples may be taken during the final rendering phase, particularly if you've specified always_sample on.

-

Note: The method to load and save radiosity data has been changed to a command line option. See section radiosity load and save for more details.

+

Note: The method to load and save radiosity data has been changed to a command line option. See section radiosity load and save for more details.

diff --git a/doc/html/r3_5.html b/doc/html/r3_5.html index eea747bf4..267b6fdcd 100644 --- a/doc/html/r3_5.html +++ b/doc/html/r3_5.html @@ -544,7 +544,7 @@
3.5.1.1.5 Height Field
[OBJECT_MODIFIER...] } HF_TYPE: - exr | gif | hdr | iff | jpeg | pgm | png | pot | ppm | sys | tga | tiff + exr | gif | hdr | jpeg | pgm | png | pot | ppm | sys | tga | tiff GAMMA: Float_Value | srgb | bt709 | bt2020 HF_FUNCTION: @@ -1148,7 +1148,9 @@
3.5.1.1.8 Lathe

You should note that the number of spline segments, i. e. curves between two points, depends on the spline type used. For linear splines you get n-1 segments connecting the points P[i], i=1,...,n. A quadratic spline gives you n-2 segments because the last point is only used for determining the slope, as explained above (thus you will need at least three points to define a quadratic spline). The same holds for cubic splines where you get n-3 segments with the first and last point used only for slope calculations (thus needing at least four points). The bezier spline requires 4 points per segment, creating n/4 segments.

If you want to get a closed quadratic and cubic spline with smooth transitions at the end points you have to make sure that in the cubic case P[n-1] = P[2] (to get a closed curve), P[n] = P[3] and P[n-2] = P[1] (to smooth the transition). In the quadratic case P[n-1] = P[1] (to close the curve) and P[n] = P[2].

-

The surface normal determination for lathes depends upon the order in which the splines points are specified. The following code will render with the color Red on the outside and the color Blue on the inside.

+

The surface normal determination for lathes depends upon the order in which the splines points are specified. For interior_texture to work as expected, the outline of the underlying 2D shape must be specified in counter-clockwise order, except for holes which must be specified in clockwise order, and they must not self-intersect.

+ +

The following code will render with the color Red on the outside and the color Blue on the inside.

 #declare Lathe_InitialOrder = lathe {
     bezier_spline
@@ -1469,7 +1471,9 @@ 
3.5.1.1.12 Prism

The bezier_spline is an alternate kind of cubic spline. Points 1 and 4 specify the end points of a segment and points 2 and 3 are control points which specify the slope at the endpoints. Points 2 and 3 do not actually lie on the spline. They adjust the slope of the spline. If you draw an imaginary line between point 1 and 2, it represents the slope at point 1. It is a line tangent to the curve at point 1. The greater the distance between 1 and 2, the flatter the curve. With a short tangent the spline can bend more. The same holds true for control point 3 and endpoint 4. If you want the spline to be smooth between segments, point 3 and 4 on one segment and point 1 and 2 on the next segment must form a straight line and point 4 of one segment must be the same as point one on the next segment.

By default linear sweeping is used to create the prism, that is, the prism's walls are perpendicular to the x-z plane. The size of the curve does not change during the sweep. You can also use conic_sweep that leads to a prism with cone-like walls by scaling the curve down during the sweep.

Like cylinders the prism is normally closed. You can remove the caps on the prism by using the open keyword. If you do, you should not use it in CSG operations, because the result may not be as expected.

-

The surface normal determination for prism sides depends upon the order in which the splines points are specified. Prism ends have normals which face outward at one end and inward at the other end. The following code will render sides with the color Red on the outside and the color Blue on the inside.

+

The surface normal determination for prism sides depends upon the order in which the splines points are specified. Prism ends have normals which face outward at one end and inward at the other end. For interior_texture to work as expected, the outline of the underlying 2D shape must be specified in counter-clockwise order, except for holes which must be specified in clockwise order, and they must not self-intersect.

+ +

The following code will render sides with the color Red on the outside and the color Blue on the inside.

 #declare Prism_InitialOrder = prism {
     linear_spline
@@ -1492,7 +1496,6 @@ 
3.5.1.1.12 Prism
}

The actual normal determination is more complicated for complex splines. If the surface normal is important to the visual result, it is best to check how the prism is being rendered by testing with substantially different inside and outside textures.

-

There is presently a inconsistency with the bezier spline mode of the prism in that the point order with respect to side surface normals is reversed from all other prism spline types. The behavior of the bezier spline prism will likely be aligned with the other spline types in a later release. Further end behavior may be made consistent for all spline types.

If additional accuracy is required you can add the sturm object modifier.

For an explanation of the spline concept read the description for the Lathe object.

See also the tutorials on Lathe and Prism objects.

diff --git a/doc/html/r3_6.html b/doc/html/r3_6.html index d9e28c40b..291161752 100644 --- a/doc/html/r3_6.html +++ b/doc/html/r3_6.html @@ -572,6 +572,9 @@

3.6.1.1 Pigment

The color or pattern of colors for an object is defined by a pigment statement. All plain textures must have a pigment. If you do not specify one the default pigment is used. The color you define is the way you want the object to look if fully illuminated. You pick the basic color inherent in the object and POV-Ray brightens or darkens it depending on the lighting in the scene. The parameter is called pigment because we are defining the basic color the object actually is rather than how it looks.

+ +

In version 3.8 there has been a Change to the pigment default setting. The default setting is now rgb <1,1,1> as opposed to the rgb <0,0,0> value used in previous versions. Requires #version 3.8; or equivalent INI setting or command-line option. See also: Version Directive.

+

The syntax for pigment is:

 PIGMENT:
@@ -1046,7 +1049,7 @@ 
3.6.1.2.3.1 Specifying a Bump Map
BUMP_MAP: normal { bump_map { - BITMAP_TYPE "bitmap.ext" [gamma GAMMA] [premultiplied BOOL] + [BITMAP_TYPE] "filename" [gamma GAMMA] [premultiplied BOOL] [BUMP_MAP_MODs...] } [NORMAL_MODFIERS...] @@ -1060,7 +1063,7 @@
3.6.1.2.3.1 Specifying a Bump Map
use_colour | bump_size Value
-

After the required BITMAP_TYPE keyword is a string expression containing the name of a bitmapped bump file of the specified type. Several optional modifiers may follow the file specification. The modifiers are described below.

+

After the optional BITMAP_TYPE keyword is a string expression containing the name of a bitmapped bump file of the specified type. Several optional modifiers may follow the file specification. The modifiers are described below.

Note: Earlier versions of POV-Ray allowed some modifiers before the BITMAP_TYPE but that syntax is being phased out in favor of the syntax described here.

Filenames specified in the bump_map statements will be searched for in the home (current) directory first and, if not found, will then be searched for in directories specified by any +L or Library_Path options active. This would facilitate keeping all your bump maps files in a separate sub-directory and giving a Library_Path option to specify where your library of bump maps are. See Library Paths for details.

By default, the bump pattern is mapped onto the x-y-plane. The bump pattern is projected onto the object as though there were a slide projector somewhere in the -z-direction. The pattern exactly fills the square area from (x,y) coordinates (0,0) to (1,1) regardless of the pattern's original size in pixels. If you would like to change this default you may translate, rotate or scale the pigment or texture to map it onto the object's surface as desired. If you would like to change this default orientation you may translate, rotate or scale the pigment or texture to map it onto the object's surface as desired.

@@ -1232,7 +1235,7 @@
3.6.1.3.1 Ambient

Note: Specular reflected indirect illumination like a flashlight shining in a mirror cannot modeled by either ambient light or radiosity. Use photons instead.

-

There has been an important Change in version 3.8 regarding the default ambient setting. When #version is set as either the first statement of the scene file or via command-line option and the version is 3.8 or greater the default setting is now ambient 0 as opposed to the ambient 0.1 value used in previous versions.

+

In version 3.8 there has been a Change to the ambient default setting. The default setting is now ambient 0 as opposed to the ambient 0.1 value used in previous versions. Requires #version 3.8; or equivalent INI setting or command-line option. See also: Version Directive.

@@ -1623,7 +1626,7 @@

3.6.1.5 Patterned Textures

} | texture { material_map { - BITMAP_TYPE "bitmap.ext" + [BITMAP_TYPE] "filename" [BITMAP_MODS...] TEXTURE... [TRANSFORMATIONS...] } } @@ -1774,7 +1777,7 @@
3.6.1.5.3.1 Specifying a Material Map
MATERIAL_MAP: texture { material_map { - BITMAP_TYPE "bitmap.ext" + [BITMAP_TYPE] "filename" [BITMAP_MODS...] TEXTURE... [TRANSFORMATIONS...] } } @@ -1784,9 +1787,7 @@
3.6.1.5.3.1 Specifying a Material Map
map_type Type | once | interpolate Type -

After the required BITMAP_TYPE keyword is a string expression -containing the name of a bitmapped material file of the specified type. -Several optional modifiers may follow the file specification. The modifiers +

After the optional BITMAP_TYPE keyword is a string expression containing the name of a bitmapped material file of the specified type. Several optional modifiers may follow the file specification. The modifiers are described below.

Note: Earlier versions of POV-Ray allowed some modifiers before the BITMAP_TYPE but that syntax is being phased out in favor of the syntax described here.

@@ -1794,7 +1795,7 @@

3.6.1.5.3.1 Specifying a Material Map
searched for in the home (current) directory first and, if not found, will then be searched for in directories specified by any +L or Library_Path options active. This would facilitate keeping all -your material maps files in a separate subdirectory and giving a +your material maps files in a separate sub-directory and giving a Library_Path option to specify where your library of material maps are. See the section Library Paths for details.

@@ -4414,7 +4415,7 @@

3.6.2.4.2 Image Pattern
IMAGE_PATTERN: image_pattern { - BITMAP_TYPE "bitmap.ext" [gamma GAMMA] [premultiplied BOOL] + [BITMAP_TYPE] "filename" [gamma GAMMA] [premultiplied BOOL] [IMAGE_MAP_MODS...] } BITMAP_TYPE: @@ -4440,7 +4441,7 @@
3.6.2.4.2 Image Pattern
} -

Note: This pattern uses an image to get the gray values. If you want exactly the same possibilities but need to get gray values from a pigment, you can use the pigment_pattern.

+

Note: This pattern uses an image to get the gray values. If you want exactly the same possibilities but need to get gray values from a pigment, you can use the pigment_pattern.

While POV-Ray will normally interpret the image pattern input file as a container of linear data irregardless of file type, this can be overridden for any individual image pattern input file by specifying gamma GAMMA immediately after the file name. For example:

 image_pattern {
@@ -4528,7 +4529,8 @@ 
3.6.2.4.4 User Defined Pattern
}
-

The pattern is similar to image_map in that it directly specifies colors rather than using a Color Map or Pigment Map.

+

The pattern is similar to image_map in that it directly specifies colors rather than using a color_map or pigment_map.

+

The user defined pattern functionality also extends to density blocks, of course using only the red, green and blue function values. See also: Density

@@ -5371,7 +5373,7 @@
3.6.2.6.1 Specifying an Image Map
IMAGE_MAP: pigment { image_map { - [BITMAP_TYPE] "bitmap[.ext]" [gamma GAMMA] [premultiplied BOOL] + [BITMAP_TYPE] "filename" [gamma GAMMA] [premultiplied BOOL] [IMAGE_MAP_MODS...] } [PIGMENT_MODFIERS...] diff --git a/doc/html/t2_1.html b/doc/html/t2_1.html index e8b432b13..1fa8139c9 100644 --- a/doc/html/t2_1.html +++ b/doc/html/t2_1.html @@ -335,11 +335,12 @@
2.1.4.1.1 Version 3.8

Language Basics and Directives

    +
  1. Important behavior changes concerning the: Version Directive
  2. Identifiers are no longer limited to just 40 characters in length
  3. Support for tau as a Built-in Constant has been added
  4. The macro directive has been extended. See Optional Parameters for details
  5. A cached macro mechanism has been implemented. See: Macro Caching for more information
  6. -
  7. Improved array functionality allows the creation of dictionary container types
  8. +
  9. Arrays now allow the creation of dictionary container types and mixed type elements. See: Array
  10. The addition of a Create_Continue_Trace_Log option allows for greater resource control
  11. The Declare and Local Directives have been extended to support tuple-style assignments
  12. All instances of gray in keywords or INI file options can now alternatively be spelled grey
  13. @@ -363,7 +364,10 @@
    2.1.4.1.1 Version 3.8

Images and Image Related

    -
  1. The default up vector has changed. See: Aspect Ratio
  2. +
  3. A new anti-aliasing method has been implemented.
  4. +
  5. Several changes to grayscale file output handling. See: Output File Type
  6. +
  7. A few changes and several additions to output file dithering
  8. +
  9. The default up and right vectors have changed. See: Aspect Ratio
  10. The max_extent function has been extended
  11. Two gamma handling specifications have been added for:
    1. @@ -375,7 +379,6 @@
      2.1.4.1.1 Version 3.8
    2. bump map input file
  12. The map_type keyword now supports the angular map projection for use with light probes
  13. -
  14. Dithering is now fully supported for Radiance HDR output files
  15. Default gamma handling of NetPBM (PPM/PGM) output files now complies with the official NetBPM standard
  16. The compression setting now affects more file types. See: Output File Type
  17. The interaction of transmit all and filter all with an image's alpha channel has been changed
  18. @@ -404,7 +407,7 @@
    2.1.4.1.2 Version 3.7
  19. mandatory assumed_gamma
  20. the srgb keyword and its kin can be used to specify gamma pre-corrected colors
  21. a File_Gamma feature has been added
  22. -
  23. an Antialias_Gamma feature has been added
  24. +
  25. an Antialias_Gamma feature has been added
  26. lastly you can also change the input file gamma for individual input files
  • Make sure to review the Images and Image Related category below for important changes and additions.
  • @@ -416,8 +419,8 @@
    2.1.4.1.2 Version 3.7
  • a revised radiosity tutorial
  • the new maximum_reuse parameter
  • adaptive pretrace mode added to the nearest_count parameter
  • -
  • the loading and saving of radiosity data has changed
  • -
  • new command line options can help to further customize radiosity features
  • +
  • the loading and saving of radiosity data has changed
  • +
  • new command line options can help to further customize radiosity features
  • The ovus object was added, along with support for uv_mapping
  • Raised max order of the poly, cubic and quartic objects. Alternate syntax is also available.
  • diff --git a/doc/html/t2_2.html b/doc/html/t2_2.html index cd78ce78c..b448cbc6a 100644 --- a/doc/html/t2_2.html +++ b/doc/html/t2_2.html @@ -1565,7 +1565,7 @@
    2.2.4.6.2 Assigning an Object to a Light Source
    } texture { pigment {color rgb <1, 1, 1>} - finish {ambient .8 diffuse .6} + finish {emission .8 diffuse .6} } } cylinder { @@ -1589,7 +1589,7 @@
    2.2.4.6.2 Assigning an Object to a Light Source

    Rendering this we see that a fairly believable light bulb now illuminates -the scene. However, if we do not specify a high ambient value, the light bulb +the scene. However, if we do not specify a high value for emission, the light bulb is not lit by the light source. On the plus side, all of the shadows fall away from the light bulb, just as they would in a real situation. The shadows are sharp, so let's make our bulb an area light:

    @@ -1607,7 +1607,7 @@
    2.2.4.6.2 Assigning an Object to a Light Source

    We note that we have placed this area light in the x-y-plane instead of the x-z-plane. We also note that the actual appearance of the light bulb is not affected in any way by the light source. The bulb must be illuminated by -some other light source or by, as in this case, a high ambient value.

    +some other light source or by, as in this case, a high value for emission.

    diff --git a/doc/html/t2_3.html b/doc/html/t2_3.html index ca019cc93..891879146 100644 --- a/doc/html/t2_3.html +++ b/doc/html/t2_3.html @@ -4501,11 +4501,8 @@

    2.3.5 Advanced Texture Options

    2.3.5.1 Pigments

    -

    Every surface must have a color. In POV-Ray this color is called a pigment. -It does not have to be a single color. It can be a color pattern, a color -list or even an image map. Pigments can also be layered one on top of the next -so long as the uppermost layers are at least partially transparent so the ones -beneath can show through. Let's play around with some of these kinds of +

    Every surface must have a color. In POV-Ray this color is called a pigment. It does not have to be a single color. It can be a color pattern, a color list or even an image map. Pigments can also be layered one on top of the next so long as the uppermost layers are at least partially transparent so the ones beneath can show through. See also: Using Transparent Pigments and Layered Textures

    +

    Let's play around with some of these kinds of pigments.

    We create a file called texdemo.pov and edit it as @@ -8938,7 +8935,7 @@

    2.3.8.5 Performance considerations

    If average to good quality radiosity will work for your scene, then it's probably a good idea to spend the time to find the sweet spot that strikes the best balance between quality and speed. Especially recursion_limit should be kept as low as possible. Sometimes 1 is sufficient, if not 2 or 3 should often be enough.

    -

    With high quality settings, radiosity data can take quite a lot of memory. Apart from that the other scene data is also used much more intensively than in a conventional scene. Therefore insufficient memory and swapping can slow down things even more. Here's a few radiosity options that might help.

    +

    With high quality settings, radiosity data can take quite a lot of memory. Apart from that the other scene data is also used much more intensively than in a conventional scene. Therefore insufficient memory and swapping can slow down things even more. Here's a few radiosity options that might help.

    Finally the scene geometry and textures are important too. Objects not visible in the camera usually only increase parsing time and memory use, but in a radiosity scene, also objects behind the camera can slow down the rendering process. See the section Configuring Radiosity for some helpful hints.

    diff --git a/source/backend/control/benchmark_ini.cpp b/source/backend/control/benchmark_ini.cpp index 42809cdf3..c683f3d7d 100644 --- a/source/backend/control/benchmark_ini.cpp +++ b/source/backend/control/benchmark_ini.cpp @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,7 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `distribution/scenes/advanced/benchmark/benchmark.ini`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). namespace pov { diff --git a/source/backend/control/benchmark_ini.h b/source/backend/control/benchmark_ini.h index 920047f91..18f4c1721 100644 --- a/source/backend/control/benchmark_ini.h +++ b/source/backend/control/benchmark_ini.h @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,7 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `distribution/scenes/advanced/benchmark/benchmark.ini`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). namespace pov { diff --git a/source/backend/control/benchmark_pov.cpp b/source/backend/control/benchmark_pov.cpp index 9833ef53a..09f019823 100644 --- a/source/backend/control/benchmark_pov.cpp +++ b/source/backend/control/benchmark_pov.cpp @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,7 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `distribution/scenes/advanced/benchmark/benchmark.pov`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). namespace pov { diff --git a/source/backend/control/benchmark_pov.h b/source/backend/control/benchmark_pov.h index 072437853..63d16b5d1 100644 --- a/source/backend/control/benchmark_pov.h +++ b/source/backend/control/benchmark_pov.h @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,7 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `distribution/scenes/advanced/benchmark/benchmark.pov`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). namespace pov { diff --git a/source/base/data/bluenoise64a.cpp b/source/base/data/bluenoise64a.cpp new file mode 100644 index 000000000..44540b9d8 --- /dev/null +++ b/source/base/data/bluenoise64a.cpp @@ -0,0 +1,307 @@ +//****************************************************************************** +/// +/// @file base/data/bluenoise64a.cpp +/// +/// Blue noise pattern data +/// Auto-generated using metagen-bluenoise.py. +/// +/// @copyright +/// @parblock +/// +/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. +/// +/// POV-Ray is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as +/// published by the Free Software Foundation, either version 3 of the +/// License, or (at your option) any later version. +/// +/// POV-Ray is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program. If not, see . +/// +/// ---------------------------------------------------------------------------- +/// +/// POV-Ray is based on the popular DKB raytracer version 2.12. +/// DKBTrace was originally written by David K. Buck. +/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. +/// +/// @endparblock +/// +//****************************************************************************** + +/// @file +/// @attention +/// **DO NOT EDIT THIS FILE!** +/// Instead, if this file needs fixing, modify metagen-bluenoise.py +/// or its invocation in `tools/meta-make/Makefile` accordingly, +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). + +namespace pov_base { + +/// 64x64 blue noise pattern data. +/// Generated using `make-bluenoise.py -i0.1 -s1.5 -r4711`. +extern const unsigned short kBlueNoise64a[4096] = { + 654,3898,1137,1753,3811,1459,3503, 344,3083, 922,2108, 719,3676,1953, 87,3726, + 2596, 270, 948,2403,3763,3375,1777,3090,1566,3363,1925,1334,3282, 493,3858,1076, + 3696,1732, 818, 190,1272,1781, 734,2105,1329,4032,2240,3226,1463,1069,2384,4054, + 1276,2162,3697,1490,2381, 576,4083, 352,2019, 634,2677, 142,2170,2562, 992,3207, + 2458,1507,3424,2623, 259,2374,2036,1147,2438, 67,3218,2702, 489,2934, 879,2277, + 3346,1580,3588,1890, 429,1242, 632,2585, 94, 841,2789, 201,1023,2580,1508,2773, + 412,2959,3443,2337,3585,2601,3194, 172,2906,1047, 250,1710,3690,2705,1969, 383, + 2781,1666,3243, 283,1183,2692,1554,3108,1144,3909,1758,3506,3093,1892,4007, 162, + 3001, 883,2057, 559,3288, 848,4053,2857,3597,1487,3963,1784,1202,2408,4060,1345, + 635,2097,2936, 770,2788,2249,3867,1386,3614,2131,4048,1693,3525,2251, 807,3295, + 2144,1203,1562, 336,2002, 926,3954,1628,3553,2615,1952,3038, 659, 4,3126, 942, + 3609, 553,2555, 804,3780,2056,3483, 3,2333,2837, 846,1336, 384, 782,1607,2152, + 3573, 362,3742,2932,1328,1836, 138,1622, 582,1031,2319, 308,3545,3184, 375,1832, + 3107, 134,1145,4026,1486,3250, 369,1991,2946,1155,2469, 477,3011,3785, 152,1789, + 4087, 680,2644,3821,3070,1454, 415,2310, 860, 518,3828,1200,2262,3927,1592,3376, + 2029,1210,3918,1838,3158, 486, 961,1724,3720, 457,3278,2272,3822,2811,3379,1117, + 1842,2709,1633,1012,2487,3649,3122,2575,2066,3350,2982, 825,1595,2127,1072,2767, + 3703,2520,3407,2183, 253,2533,1044,3468, 697, 280,3270,1446, 713,2006,1371,2900, + 316,3554,1874,1086, 615,2744,3390,1928,2941,1397,2463,3408, 876,2604,1292, 251, + 2439,2987, 85,2294,1365,2814,2440,3025,1402,2063,1073,2652,1509, 206,2372, 563, + 4086, 61,2293,3910, 298,2151, 756,1229,3920, 173,1871,3817,2666, 5,3891, 741, + 1398, 490,1717, 703,3037,1821,3941,1539,2672,1882,3852,2174,2765,1118,3470,2461, + 959,2188,3142, 199,2362,3671,1236, 50,3750,3203, 223,1664, 371,1900,2834,3771, + 745,1649,3348,1016,3570, 205,3979, 682,3414, 136,4045, 590,1954,3717,1273,3212, + 791,1420,3385, 630,3022,1524,3410, 473,2762,1414,2368, 546,1332,3434,2392,1958, + 3308,2287,3838,1287,3658, 899, 40,2300,3152,1253, 858,3516, 78,3950, 451,3223, + 1627,2719,1315,3948,1605,2024, 816,2531,1759,1071,2089,4069,3047,3623, 514,2221, + 1135,4043,2614, 531,1608,2208,1893,1157,2724,2406,1773,3035,3425, 947,2928,2095, + 2648,3112,1175,1897,2620, 987,3801,1787,3183, 869,3681,2844, 991,3082,1639, 246, + 2898, 984, 109,2563,2058,2775,3388, 585,3774, 220,2992,1526,2442,1763,2284, 777, + 3864, 7, 723,3413,2831, 262,3306,3868, 505,2823, 760,2336,1432,1042,3296,1744, + 2911, 303,1999,3128,3787, 757,3289, 402,1576,3595, 837,1343, 388,2429, 133,1570, + 442,2256,3832, 208,3555,2110, 35,2530,2198, 354,3402,1815,2165, 439,3651,1240, + 3994,1798,3120,3539, 381,1493,1085,2168,1703,2573,1990, 387,3344,1048,3003,1375, + 2090,3524,1841,2485, 925,1437,2962,2227,1577,3279,3679, 120,2745, 665,2501, 64, + 3582,1505, 891,2449,1244,2849,2347,3887,2938, 233,2225,3912,2768,1700,3845,3482, + 1857,1000,2840,1653, 829,2979,1449,1054,3965,1660,1248, 105,4091,2512, 884,2690, + 591,2345,1443, 862,1902,3224,4090,2860, 827,3552,1167,4016,2656, 544,3747, 327, + 2856,1098,3067, 453,2163,4030, 619,1149, 307,2480,1255,1803,3497,2040,3978,1281, + 2180,3215,3729, 376,1848, 42,1458, 976,1978,1216,3117, 568,2012,3256,1193, 733, + 3645,3181, 373,2427,4035, 506,3258,2697, 674,3042,2576,3195, 720,1549,3479,2102, + 3287, 329,2865,3900, 621,2424, 140,1349, 463,3118,2318, 740,1482,1946,3236,1585, + 2522, 629,3650,1297,3239,1720,2606,3620,1987,3916, 898,2897, 452,1569,3148, 819, + 2730, 475,1121,2671,4011,3024,3562, 494,3381,2649,3692,1548, 985, 293,2231,2735, + 188,2120,1399,3421,1146,2285,1687,3490, 313,2076, 957,3699,1907,2861, 288,1350, + 1713,3778,1156,2126,2721,1616,3474,2075,3792,1537, 52,2832,3472, 915,2266, 145, + 4089,1768,2322, 112,3758, 335, 977,3077,1412, 171,3180,2149,3783,1106, 257,2953, + 1686,1972,3333,2202, 743,1617,2506,2114, 775,1755, 90,2475,3536,2967,3990,1521, + 1061,3808, 589,2722,1975, 117,3728,1279,2404,3878,1445, 492,2359,1132,3892,3058, + 689,2471, 24,3522, 946, 306,3010,1043,2590,1822,3664,2128, 396,3901,2738,1232, + 3341, 855,2780,1462,2053,2912,2360, 539,3386,2685,1671, 655,2569,3298,2331,3705, + 646,3923,1337, 310,3445,1084, 198,3665,3063,1179,4061, 735,2107,1359, 605,2505, + 2994,1647,3238, 895,3882,2955, 802,1937,3099, 139,1794,2944,3340, 71,2257, 920, + 3594,1983,3225,1325,2913,1863,3972, 602,3214, 787,1142,3023,1381,1807, 532,3040, + 1981, 408,3804,3166, 705,1190,3544,1791,2195, 831,4040,1322, 28,1917,1465,1001, + 2629, 81,2405,3106,1805,3818,2855,1394,2329, 401,1905,2884,3276, 149,1866,3432, + 2210, 65,2484,1796, 311,1525,2470, 533,1090,3465,2640, 847,3644,1536,2782,1840, + 403,2633,1572, 507,3737,2466,1433,2211, 163,3881,2477, 274,3365,2584,1015,3528, + 1501,2426,1063,1746,2595,3999, 58,1342,3691, 358,2378,3463,2883,3872, 438,3389, + 2027,3619,1600, 873,2653, 556,2004, 861,3859,3419,2521,1511,1008,3895,2760, 857, + 526,4085,1079,3513,2177,3114,3596,2776,4055,2137, 414,1270,2010, 612,4044,1316, + 3145,1038,3985,2288, 842, 351,3325,1176,2871,1955,3505,1662, 673,3806,2346, 14, + 3942,2852, 241,3394, 487,1993,3263,2787,1004,3008,1963,1081,1734, 835,2212,2981, + 1211, 716,2805,4075,1246,2302,3320,1682, 33,1299, 649,3730, 360,2364,1282,3575, + 1930,2910,1434,2634, 661,1300, 911, 240,1408,1674,3138,3775,2564,3044, 304,2421, + 3674, 130,2801,1908,3444,1646,2641,3713, 515,1477, 924,2255,2956,1223,1891, 808, + 2078,1251,3655,2199, 969,1512,2417, 622,1631,3813, 143,3248, 572,2720,3592, 278, + 1775,3213, 423,2071, 132,3672, 455,2559,2902,3208,2176,2696,1696,3159, 248,1541, + 3303, 788,3735, 411,3220,3958,1853,2344,3312, 672,2385, 263, 971,1621,3338, 747, + 2129,1506, 595,1233,3021, 88, 951,1765,2376,3100,3969, 97,3318, 426,2774,3446, + 3071, 636,1644,2684,3819,2990, 267,3476,2118,2612,1274,2434,4003,1444,1014,2534, + 3940,2369,1347,3372,2927,1573,1119,3964,1970, 936, 433,3383,1150,2074,3810,2627, + 2194, 150,2366,1676,2026, 13,2689,3638,1066,2917,3896,1812,3557,2273,1140,1864, + 3449,2975,3888,2515,3603,2142,4067,3217, 225, 779,2736,1373,2092,1707,4050,1439, + 343,2380,3253, 114, 742,1305,1827,4082, 806, 434,3543,1830, 322,2083,3124,1601, + 116, 953,3764,1829, 833,2474,3119, 666,1468,3635,1814,4029, 784,2893, 597,1049, + 3988,1348,2838,3496,1101,3018,1491, 523,2166, 164,1340, 761,2833, 6,3944,2594, + 275, 940,1716, 389,1096, 626,2791,1324,2041,3535,1088,2456,3715, 724,1035,2535, + 1859,3877,1138,1995,3423,2540,3125,1107,2750,1531,3052, 928,2799,3741, 503,3428, + 2007,3032, 584,2687, 333,3493,2161, 151,2432,2802, 353,1417,2532, 53,3234,1783, + 379,3364, 902, 536,3879,2422, 859,3827,1745,3511,2525,1986,3267,1452, 603,2919, + 1296,3762,2274,3316,1977,1559,2460, 328,3793,1665, 521,3435, 244,2694,3169, 74, + 3533, 880,2741,1552,3951, 499,2187, 45,3371,2309,3915, 166,2218,1358, 817,2592, + 1171,3633,2283,1441,4005,1051,1747,3833,3219,1161,2214,3113,1951,3500,1519,2459, + 3095,1883,2578,1594,2125, 319,3357,2793,1154,3081, 428,4006, 990,2358,3732,1685, + 2119, 687,2660, 57,2873,3719,3401, 901,3002,2268,2825,1429,1843,2236,3781,1335, + 2153, 538,3186, 204,2301, 972,1709,3710,1341, 522,1738,1168,3351,2939,1839,3830, + 374,1657,2877, 18,1982,2942, 472,1393, 799,3485, 195,3794, 865,1205,3694, 728, + 1083,3917, 174,3537,3155,1263,1935, 102,2308, 732,1540,2699, 349,1895,3087, 156, + 3567,3173,1470,3991, 772,1256, 482,1885,1206, 22,3886, 828,3074,1128, 574,1699, + 3039,2455,3709,1314,2940,3510,2676, 696,2035,3257,2622,3608, 647,2445, 69,3177, + 2209, 718,3499, 909,3307,2382,3593,2727,2093,1715, 650,2915,2340, 338,2783,2112, + 2961,1406,2259,1011, 599,2625,4093,1612,3586,3244,2064,3698,1277,3461, 776,1189, + 2481, 436,1074,1846,2391,3132,2167,4025,3232,2599,2015,3349, 305,3986,2772,3480, + 269,1022,1767, 678,1945, 364,1214,4001,2885, 939, 242,1961,1534,4034, 986,1376, + 2733,3966,1222,2537,1604, 651,1195, 128,3085,3874,2626,1362,1835,4049,1578, 107, + 3751, 541,2755,3662,1774,2998, 821, 398,2558,1007, 527,2984, 177,2430,2820,1642, + 3904,2039,2991,3498, 229,1619,2734, 281,1496,1017, 537,1565,2473,1898, 908,2084, + 1410,4063,3322,2607,3866,3216,2339, 127,1618,2393,3829,2976, 440,2172,3416,1730, + 289,1904,3249, 227,3718,1881,4095,2328,1476, 407,1068,3581,3162, 578,3384,2524, + 830,3292,1956, 393,1451,2330,3714,2042,1331,3885,1809,2289,1478,4051,1967, 321, + 3259, 903,2710, 592,3857, 966,3634, 715,2315,3814,3457,2916,1275,3661, 86,2418, + 2845, 483,2246, 10,1457, 793,1778,3060,3478,1369, 676,1109,3227,2668, 765,3752, + 3054, 606,2276,1383,2966, 361,3149, 943,3429,2011,2415, 11, 904,2206,1185,1865, + 1533,2411,1221,3939,3409, 181,1162,3105,2743, 23,3484, 795,3189, 581,1027,3504, + 1436, 103,1669,2143,2568,1391,1971,3324,2822,1779, 126,2106, 700,3079,1609,3824, + 789,3129,1635,1093,2914,2132,3767,1032, 488,2786,2192,3622,1431, 125,2003,1280, + 2523,1070,3897,2698, 785,2082,2608,1689, 691,2901,3975,1742,2609,3027,3889, 332, + 3618,3088, 44,2835, 759,2579,1858, 577,3355,1543,2447,1177,2715,3724,2157,2899, + 2492,3744,3146,1207,3366, 47,3056, 464,1241, 823,2542,3591,1104,2611, 551,3370, + 1260,1957,3518,3805, 548,3284, 218,2603,1966,4066, 191,1770,2510,3930,2890, 365, + 3546,2060, 75,1663,3412,1087,3856, 95,3653,1294, 479,3266,1495, 217,2033,2737, + 607,2103, 933,2220,1650,3206,4019, 954,2226, 366,3967,1899, 157,1691, 377,1269, + 693,1903, 458,4070, 749,2377,1694,3765,2160,3955,1466,3193, 279,4028,1833,2232, + 159,2631, 370,2286,2729,1683,1231,3571,1545, 889,2949,3395, 706,1037,1712,3290, + 1538, 832,3104,3648, 448,2478,1428,3221,1933,2701,2264,1124,3711, 812,3415,1065, + 4084,1718,3378,3797,1278, 427,2059,1357,3578,2874, 653,3055,3540,2597,3241,3981, + 2252,3013,1097,2769,2008,3613,1024,2598, 176,2964, 580,1735,2321,1338,3229, 930, + 3748,3026,1009,1418, 780,3914,2416, 613,3168,2281,1258, 331,2086,3111,2304, 611, + 4057,2804,2353,1239,1994,3030, 639,2314, 921, 264,3551, 669,2808,1786,2443,1423, + 2904, 491,2488, 238,2706,3670,3009, 141,2548,1737,1080,2130,1346, 722,1013,1568, + 146,3404,1750, 210,1352,2989, 604,1544,3487,1136,2022,3643, 834,2908, 470,2529, + 1500,1797,3977,3331,1926, 325,2954,2050, 56,3860,2628,3565,1528,3738, 15,2593, + 1166, 236,1817, 677,3953, 202,3514,1726,4020,2985,1636,2052,3943, 437,3191, 123, + 1973,1198,3179,1558,1041, 712,2312,1589, 844,3770,3200, 430,3919,2431,1948,3616, + 2717, 867,3893,2536,3501, 350,3971,2282,3187, 395,2842,2476, 16,3816,1949,3447, + 243, 686,2395, 79,2777,3617,1108,3368,1415, 758,1847, 465,2792, 800,1351,3488, + 2030,3178,3745,2544,1598,2821,1178,2661, 368,1310,3405, 60,2557,1165,2193,3766, + 2658, 815,3906,2038,3515,1844,3313,3908,2819, 254,2361,1535,2779, 38,3045, 557, + 2350,1442,2147, 623,1629,2100,2713, 838,1845,1401,4010,1005,3326,1483,1060,2815, + 2219,3663,2935,1191,1560,2215, 863,1751,3680,2335,3062,1082,2182,3922,1795,2997, + 885,1479, 330, 982,3403,2135, 767,3740,2021,2389, 988,3157,1510,3492, 570,1591, + 3076, 165,2388, 573,2829, 32,1304, 529,1164,1867,3343, 874,3657,1740,3448,1257, + 3757, 256,3286,2867, 980,3237,1228, 168,3721,2386, 681,1698,2164,2714, 593,4088, + 1354, 850,2014,3274, 617,4033,2669, 454,2826, 299,4012,1634,3188, 185,2399, 413, + 3862,2204,3532,2965,1377, 39,3211,1620, 586,2887,3846, 729,1901,2824, 932,3626, + 1268,1799,3265,1379,3809,2577,3139,2099,2541,3572, 567,2203,1194, 385,2122, 843, + 2790,1922,1173,3577, 21,3759,1906,2957,3377, 334,2797,3161, 224,3556,1854, 296, + 3233,1704, 394,3563,2482, 170,3141,1992,1226,3314, 941,2566, 664,3430,1181,2817, + 727,2621,1752, 530,2420,4094,2600,1078,3549, 167,1411,2527, 265,3993,2292, 315, + 2554,4038, 989,2158, 339, 905,1530,4092, 207,2988,1419,2862,3980,2511,3293,1502, + 4047, 525,2587,1757,2263, 663,2553,1522,1036,2104,1283,3685, 918,2496,1266,2996, + 2338,3844,2650, 974,1819,1364, 778,3803,1574,2248, 135,1950,1384,3707,2091,1571, + 3321, 89,1192,3659, 912,1869, 450,2081,3121,1739,2229,3466,3046,1312,1711,3360, + 2094, 683,2847,3700,1725,3393,2316, 684,1741, 923,3784, 92,1690, 711,2983, 178, + 2247,3175, 809,3850,1407,3096,4068, 469,2462,3870,1820, 550,1582,3928,2085, 670, + 1125, 55,1499,3084,3902,2139,3442,2436, 566,3576,2971,3839,2723, 481,3072, 952, + 4015,1927,2880,2223,3285,1481,3786,2813, 781,3974,1120, 616,2018, 836,2739, 498, + 3589,1515, 113,2401, 555,2950,1115,3632,3156,2379,1989,2647,1094,3471,1909,1025, + 3628,1637, 302,2895,1100, 226,1785, 919,3462, 99,3078,2667,3418, 131,3150,2582, + 3693,3334,2254, 657, 359,2763,1089, 25,2695,1163,1695, 397,1045,2351,1808, 213, + 2433,1396,3782, 300, 737,3017, 148,1306,2367, 290,2726,3683, 12,3163,3840,1131, + 3012,1918,3242,1295,3559,2016, 73,2700, 417,1250,3367, 337,3686,2305, 519,2746, + 1321,2539,2047,3441,2326,3636,2659,2138,2843,1438, 803,2317,1143,1911, 866,1471, + 460,1714,2848,1245,3606,1624,3268,1941,4081, 714,3436,2123,3251,3949, 753,3167, + 3568, 575,1057,2686,1708,2490,3426,1924,3624,1584,3199,1825,2489,1460,2239, 219, + 2503, 955,3924, 746,2618,1610,3899,1382,1880,4008, 645,1632,2881,1361,3854,3196, + 66,3959, 978, 501,1602, 752,3247,1267, 540,3612,2017,4023, 444,2809,3863,3387, + 2055, 801,4024,1913,2486, 273, 894,3005,1405,2363,2846,1313, 144,1513,2638,1188, + 2140,2930,3361,2043,4000,1213, 554, 934,2655, 420,1224, 690,4021, 962,3450,1680, + 3673, 431,2196,2970, 291, 983,2234,3300, 852,2444,3051,2116, 907, 245,1702,2178, + 774,1824,2665,3109,3826,1965, 54,3970,1721,3153, 249,1611,3086,1293,2370, 222, + 2662,3136, 106,1019,2958,3894,2241,3460, 447,1856, 295,3756,3015,1920,3667, 461, + 1722, 258,1523, 856, 26,3526,2155,3143,3956,2245,3398,2892,2045, 445,2816, 704, + 1235,2732,1450,1816,3788,3197, 596,2866,3598, 378,1201,3749,3311,2514,2973,1148, + 3604,3339,1455, 192,1172,2479,2951,1059,2190,2617, 906,2441,3716, 644,1728, 958, + 3802,1311,2413,3534, 608,1372,1749, 771,2602,3861,1010,2502, 658, 965,3315,2365, + 4074,2565,3706,3057,2390,2841,1597, 184,1327, 783,1780, 101,3566,1302,2173,3115, + 1943,3997, 34,3508,1158,2465,1754, 137,2044,1599,2708, 30,1818, 707,4072, 345, + 2423, 562,2096,2876,3475,1542, 600,3382, 340,3796,1366,3400, 59,2169,3521,3006, + 1889, 545,1615,3255,1996,2757, 169,3599,1220,2929,1588,3547,2068,2752, 68,1425, + 762,1141,1979, 638,1409,1002,3769,1877,2968,2509,3825, 999,2643,1651,3795, 189, + 2451,3262, 878,2324, 356,2785,1333,3883, 997,3245,3968,2275,1064,3464,1529,1939, + 2803,1254,3983, 424, 896,2280,3849,2742,1625, 709,2926,1896,1127,2872,1430, 301, + 2528,3600,2185, 268,1180,3789,2299,3205,2020, 84,2260, 363,1374,3933,1782,3165, + 2859,3509, 214,3202,3945, 405,2267, 695,3637, 284,1448,3073,2235, 348,3337,1034, + 610,1668,3019,2031,3323, 797,3530,2186,2549, 692,1390, 513,3103,2642, 180,3656, + 935,3277,1638,2552,3687,1862, 237,1111,2013,3294,2323, 466,4077,2491, 738,3903, + 1091,3091, 887,4058,2907, 380, 944,1564, 625,4037,3328,3031, 583,3431,1056,2222, + 516,1826,2681,2181,1623,2574,3362,2748,1113,3246,1998, 561,4078, 810,2909,1498, + 2703,3733, 485,1380,4079,1658, 508,3049, 221,1697,2886,3669,2037,1247,2352,2986, + 633,2261, 36,3075,1326, 662,3176,2493,3938, 100,1262,3602, 931,1788,3309,2046, + 1581, 8,2670,1480,1834,2500,3089,3682,2718,1092,1802, 868,2635,2349, 286,3702, + 1492,3869,1264, 913,3625, 77,1317,2034, 478,1656,2467,3358,1290,1870,2303,3890, + 400,1878, 981,2556, 118,2863,1934,1238,3746,3380,1915, 111, 864,3934, 462,1467, + 3873,1800,3491,1053,2028,2818,3550,1440, 853,2978,1692,2610,3140, 186, 558,2798, + 3689,2279,3417, 699,3621, 471,1339,1964, 216,2428,1473,3768,1929,1249,3053, 854, + 2545, 110,3297, 542,2800,1769, 813,3989,2882,3779, 914, 175,2766,3627, 63,1151, + 2115,3352,2952,3610,2243,1067,3853,2313, 748,2632,1062,2402,3254,1672,3439,2070, + 1129,2728, 441,2446,4064, 187,1733, 502,2148,3458, 390,2073,1469,3851,2355,1289, + 824, 410,1938,1259,3192,2216,3937, 736,2977,3560, 459,2836, 29,3976,1688,3517, + 2001,2980,2343,4052,2061,3080,3456,2306, 231,1344,3486,2156, 652,1593,3092,3512, + 2651, 235,1261, 694,1575,3299, 252,3135,1555, 409,4014,1360,2850, 601,2678, 161, + 3101,3754, 822,1586,3151, 975,2357,3776,2753,1126,4002, 717,2878,1050,1884,3473, + 3007,3926,2538,2889, 247,1029,1723,3342,1218,2077, 820,3272,2175, 701,2740, 425, + 1187, 675,1563,1028, 277,1400, 565,1075,1873,2591,2999,1727,3952,2517, 927,1422, + 3998,1652,2397,3884,1968, 547,2526, 963,3574,2145,3028, 266,1944,3772,1052,2398, + 399,1356,2217,3611, 571,2680,1303,3281, 129,1860,2452,3353, 49,3736,2583, 314, + 1547,1018,1679, 624,3837,2400,2810, 91,2560,3995,1748,1152,3615,1550,3174,2271, + 3800,3269,1931,3523,2472,3807,2704,3204,3640, 750, 419,1105,3201, 260,2242, 552, + 3050, 875,3171, 1,2778,3502,1389,1872,2691, 656,1736,3629, 840,2233,1489,4042, + 3335,1940,2931, 70,1811,3907,2054, 754,1553,3134, 960,1404,2197,1684, 637,3261, + 2228, 83,3538,2080,3291,1435, 679,3678,1546, 391,3123,2645, 194,2499, 937, 276, + 1456,2613, 153,2851, 786,1705,2146, 2,1497,2407,3841,2000,1388,3548,2875,1849, + 342,2072,3639,1134,2290, 796,4036,2969, 82,3834,1139,2508,3133, 0,2828,1776, + 500, 996,2572,3459,1197,3004, 346,3569,2619,3848, 285,3020,3579, 890,2853,1298, + 4013,2683,2993,1217, 182,1886,3098,2121,1077,2375, 640,3842,1387,2005,4046,3481, + 1806, 618,3962,1323,3137, 347,1196,4031,2830, 964,3391, 104,2639, 668,1026,3688, + 1252,2636, 614,1504,3271,1760, 309,1225,2332,3332,1532, 372,3467,1301,3607, 744, + 3066,3731,1527, 641,2311, 917,1677,2224,1208, 628,2341,1959, 406,2396,3777,1985, + 524,1766, 814,3727,2495, 916,4080, 324,3427,2974,1852,1003,3304, 456,2796,1237, + 3068,2325, 970,2065,3695,2356,3489,1921, 579,2258,1587,3043,2184,4041,1516,2468, + 3154,3911,1910,2905, 421,3723,2113,3160, 764,1916,2869, 929,1810,2654,2154,1160, + 2454, 326,2117,3992,2707,3198,3799, 209,3452,2894,1626,4065,1182,3190, 115,1030, + 3519,2419,1472, 382,3369,2879,1320,2588,1643, 46,3668,2265,2921,1654, 768,2133, + 43,3433,2664, 435,1484, 725,2960,1058,3230, 294,3654,1199, 367,1801,3397, 122, + 1661, 938, 200,3454,2464, 998,2751,1461,3605, 484,3996,2412,3743, 642, 272,3932, + 1855,3283,1288, 154,1831, 480,1392,2497,1912, 973,3327, 512,2794,1837,1447,2657, + 3069, 203,3843,2141,1675, 467,2253, 731,3558,2712,1355, 805, 179,3704,2637,3880, + 1110,1614,3798,1861,3347,2716, 147,1670,3865,2624,1876, 643,3264,2771, 849,2269, + 2870,3561,2334,1234,1645, 627,3855, 211,2581,1099,2101, 108,1385,3014,3336,1579, + 2749, 773,2945,3437, 870,3641,2922, 708,3957, 17,1403,2516, 798,3815,3422, 588, + 2088,1243,3182,2761,1020,3921,3102,1914,1116, 497,3961,1988,3374,2354,1416, 509, + 3147, 702,2963, 215, 950,4004,2023,2437,1363, 888,2948,3790,2425,1291,3647, 535, + 1378,1976, 726,4071,2947,3319,1894,2320,3235,1567,2924,3411, 851,1919,2348,1006, + 196,3831,2200,1603,2605,1974,1095,2171,3116,2674,1792,3675,2159, 234,2371,1681, + 4039, 871,1850, 660,3477,1424, 212,3734,2450,3231,1706,3016,1130, 320,1851,3527, + 2414,1960,1309,2238,2547,1227,3130, 620,3396, 51,2136,1046,1648, 197,2048,3973, + 48,3280,2688, 392,2067, 93,1318, 949, 418,3812, 631,1762,2679,4076, 476,3630, + 1426,2518, 422,1170,4059, 96,3302,1556, 474,1133,3392, 357,3059,1308, 956,2920, + 282,3564,2630, 9,2435,2062,2864, 826,1561, 155,2297, 587,2589,4073, 886,2839, + 160,3936,3275, 495,3739,1772, 292,3652,1590,2570,4062, 404,3494,3094,2673, 995, + 2453,1756,1102,3708,1518,2586,3925,3455,2756,2191,1212,3677, 228,1112,2087,2972, + 3273,1771,3531, 667,3034,2327, 386,3725,2383,3871,2069, 872,1667,3947,3310,2546, + 1427,2201,3260,1613,3684, 517,1169,3373,2675,3875, 968,3660,1520,2150,3097,1230, + 1659, 766,2693,1551,3453, 839,2764,2244, 792,3048,1215,1823,2298, 609,1474,3420, + 3836, 564,3170,2270, 811,3029, 534,1606,1936, 19,3041,2394,3228,1655,2571, 755, + 62,1039,2858,2111,1284,3584,1813,1021,2795, 648,1368,2854,2498, 121,1875, 698, + 3722, 416, 910,1265,3000,1793,4056,2179, 432,1962,1367,2747, 41,3301, 520,2009, + 3666,2307,1103, 20,2079,3061,1174,3913,1942, 496,3587,2807, 900,3755,1923, 323, + 2124,1583,2806, 239,3542,1204,2387,3172, 739,4022,1453, 881, 543,3601,1319,3905, + 1879,2410,3753, 232,1640,2663, 751,3131,1947, 76,3580,3252, 560,3646,2278,1114, + 2943,2032,2711,3835, 688,2543, 255,1464,3209, 710,3033,3495,1804, 845,3847,2784, + 312,3345,2923,4017,2513, 528,1503, 119,3440,2448,1413, 317,3210,2494,1153,2937, + 3330,1285, 893,4018,1673,2025, 158,3701,1055,2230,3356,1828,2868,2134, 297,2725, + 3469,1421, 790,3240,3931, 504,3451,1475,4027,2561,1701,2189,1209,1557,3064, 341, + 3935,1678,3399, 124,2237,3529, 897,2812,3820,2342,1122, 318,2507,1286,2250,1488, + 994,1790, 594,1307,1719,3760,3305,2616,1729,1033,3984,2109,1630, 80,3960, 763, + 355,3642,2551,2213, 510,3406,2918,1353,2550, 446,2770, 183,3946, 979,3317, 671, + 2207, 449,2759,1984,1123,2483,2098, 287,1184,2995, 945, 271,3982, 769,3438,2646, + 1370, 569,1040,1980,1494,3144,1159,1888, 72,1596,3590,1997,3929,2925, 193,3507, + 2519,3823,2051,3164, 230, 967,2205, 730,3185, 261,2933, 794,3354,2758,1761,2291, + 2827,1932, 31,3110, 993,2682, 685,1887,3876,1641,3520,1271,2457,1485,3065,1731, + 1186,3987,3127,1514, 27,2896, 892,3791,2295, 549,3712,2409,2888,1764,2049, 37, + 2296,3222,2567,4009,2891, 443,3773,2504,3329, 598,2731, 882, 468,3359,1743, 721, + 3036, 98, 877,2754,3541,1868,2903,1330,3631,2373,1517,3761,1219, 511,3583,1395, + }; + +} diff --git a/source/base/data/bluenoise64a.h b/source/base/data/bluenoise64a.h new file mode 100644 index 000000000..2e250ceae --- /dev/null +++ b/source/base/data/bluenoise64a.h @@ -0,0 +1,48 @@ +//****************************************************************************** +/// +/// @file base/data/bluenoise64a.h +/// +/// Blue noise pattern data +/// Auto-generated using metagen-bluenoise.py. +/// +/// @copyright +/// @parblock +/// +/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. +/// +/// POV-Ray is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as +/// published by the Free Software Foundation, either version 3 of the +/// License, or (at your option) any later version. +/// +/// POV-Ray is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program. If not, see . +/// +/// ---------------------------------------------------------------------------- +/// +/// POV-Ray is based on the popular DKB raytracer version 2.12. +/// DKBTrace was originally written by David K. Buck. +/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. +/// +/// @endparblock +/// +//****************************************************************************** + +/// @file +/// @attention +/// **DO NOT EDIT THIS FILE!** +/// Instead, if this file needs fixing, modify metagen-bluenoise.py +/// or its invocation in `tools/meta-make/Makefile` accordingly, +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). + +namespace pov_base { + +extern const unsigned short kBlueNoise64a[4096]; + +} diff --git a/source/base/font/crystal.cpp b/source/base/font/crystal.cpp index 26ca51cf1..9f8ad2849 100644 --- a/source/base/font/crystal.cpp +++ b/source/base/font/crystal.cpp @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,7 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `distribution/include/crystal.ttf`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). namespace pov_base { diff --git a/source/base/font/crystal.h b/source/base/font/crystal.h index 2dd10735e..1ec1da1e6 100644 --- a/source/base/font/crystal.h +++ b/source/base/font/crystal.h @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,7 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `distribution/include/crystal.ttf`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). namespace pov_base { diff --git a/source/base/font/cyrvetic.cpp b/source/base/font/cyrvetic.cpp index ef0b6cdec..4d3d75aa6 100644 --- a/source/base/font/cyrvetic.cpp +++ b/source/base/font/cyrvetic.cpp @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,7 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `distribution/include/cyrvetic.ttf`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). namespace pov_base { diff --git a/source/base/font/cyrvetic.h b/source/base/font/cyrvetic.h index 497f53ee5..a914f9880 100644 --- a/source/base/font/cyrvetic.h +++ b/source/base/font/cyrvetic.h @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,7 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `distribution/include/cyrvetic.ttf`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). namespace pov_base { diff --git a/source/base/font/povlogo.cpp b/source/base/font/povlogo.cpp index 73535804a..7ad3721a0 100644 --- a/source/base/font/povlogo.cpp +++ b/source/base/font/povlogo.cpp @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,7 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `distribution/include/povlogo.ttf`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). namespace pov_base { diff --git a/source/base/font/povlogo.h b/source/base/font/povlogo.h index a5fcf8ca2..bb2794835 100644 --- a/source/base/font/povlogo.h +++ b/source/base/font/povlogo.h @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,7 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `distribution/include/povlogo.ttf`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). namespace pov_base { diff --git a/source/base/font/timrom.cpp b/source/base/font/timrom.cpp index 0235458de..ae4e2e3e3 100644 --- a/source/base/font/timrom.cpp +++ b/source/base/font/timrom.cpp @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,7 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `distribution/include/timrom.ttf`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). namespace pov_base { diff --git a/source/base/font/timrom.h b/source/base/font/timrom.h index 64e83c20a..f7aed3bec 100644 --- a/source/base/font/timrom.h +++ b/source/base/font/timrom.h @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,7 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `distribution/include/timrom.ttf`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). namespace pov_base { diff --git a/source/base/image/dither.cpp b/source/base/image/dither.cpp new file mode 100644 index 000000000..d1fc259cb --- /dev/null +++ b/source/base/image/dither.cpp @@ -0,0 +1,429 @@ +//****************************************************************************** +/// +/// @file base/image/dither.cpp +/// +/// Implementations related to image dithering. +/// +/// @copyright +/// @parblock +/// +/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. +/// +/// POV-Ray is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as +/// published by the Free Software Foundation, either version 3 of the +/// License, or (at your option) any later version. +/// +/// POV-Ray is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program. If not, see . +/// +/// ---------------------------------------------------------------------------- +/// +/// POV-Ray is based on the popular DKB raytracer version 2.12. +/// DKBTrace was originally written by David K. Buck. +/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. +/// +/// @endparblock +/// +//****************************************************************************** + +// Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config) +#include "base/image/dither.h" + +// Standard C++ header files +#include + +// POV-Ray header files (base module) +#include "base/data/bluenoise64a.h" + +// this must be the last file included +#include "base/povdebug.h" + +namespace pov_base +{ + +//******************************************************************************* + +void NoDither::GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) +{ + offLin.clear(); + offQnt.clear(); +} + +//******************************************************************************* + +class OrderedDither::Pattern +{ +public: + template Pattern(unsigned int size, const T* raw, unsigned int rank); + template Pattern(unsigned int size, const T* raw); + Pattern(std::initializer_list> raw); + ~Pattern(); + inline unsigned int Size() const { return mSize; } + inline const ColourChannel& operator[](size_t i) const { return maData[i]; } + const ColourChannel& operator()(unsigned int x, unsigned int y) const; +private: + unsigned int mSize; + ColourChannel* maData; +}; + +template +OrderedDither::Pattern::Pattern(unsigned int size, const T* raw, unsigned int rank) : + mSize(size), + maData(nullptr) +{ + auto flatSize = size_t(mSize)*size_t(mSize); + maData = new ColourChannel[flatSize]; + ColourChannel invRank = 1.0 / rank; + for (unsigned int i = 0; i < flatSize; ++i) + { + POV_ASSERT(raw[i] >= 0); + POV_ASSERT(raw[i] < rank); + maData[i] = ColourChannel(raw[i] + 0.5) * invRank - 0.5; + } +} + +template +OrderedDither::Pattern::Pattern(unsigned int size, const T* raw) : + Pattern(size, raw, size_t(size)*size_t(size)) +{} + +OrderedDither::Pattern::Pattern(std::initializer_list> raw) : + mSize(raw.size()), + maData(nullptr) +{ + auto flatSize = size_t(mSize)*size_t(mSize); + maData = new ColourChannel[flatSize]; + auto rank = flatSize; + ColourChannel invRank = 1.0 / rank; + ColourChannel* pCoeff = maData; + for (auto&& rawRow : raw) + { + POV_ASSERT(rawRow.size() == mSize); + for (auto&& rawCoeff : rawRow) + { + POV_ASSERT(rawCoeff < rank); + *(pCoeff++) = ColourChannel(rawCoeff + 0.5) * invRank - 0.5; + } + } +} + +OrderedDither::Pattern::~Pattern() +{ + if (maData != nullptr) + delete[] maData; +} + +const ColourChannel& OrderedDither::Pattern::operator()(unsigned int x, unsigned int y) const +{ + return (*this)[wrap(y, mSize) * mSize + wrap(x, mSize)]; +} + +//------------------------------------------------------------------------------ + +OrderedDither::OrderedDither(const Pattern& pattern, unsigned int width, bool invertRB) : + mPattern(pattern), + mImageWidth(width), + mInvertRB(invertRB) +{} + +void OrderedDither::GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) +{ + offLin.clear(); + ColourChannel off = mPattern(x, y); + offQnt.red = (mInvertRB ? -off : off); + offQnt.green = off; + offQnt.blue = (mInvertRB ? -off : off); + offQnt.alpha = off; +} + +//******************************************************************************* + +void DiffusionDither1D::GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) +{ + if (x == 0) + offLin.clear(); + else + offLin = lastErr; + offQnt.clear(); +} + +void DiffusionDither1D::SetError(unsigned int x, unsigned int y, const ColourOffset& err) +{ + lastErr = err; +} + +//******************************************************************************* + +SierraLiteDither::SierraLiteDither(unsigned int width) : + imageWidth(width), + maErr(new ColourOffset[width+2]) +{} + +SierraLiteDither::~SierraLiteDither() +{ + delete[] maErr; +} + +void SierraLiteDither::GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) +{ + offLin = maErr[x+1]; + offQnt.clear(); +} + +void SierraLiteDither::SetError(unsigned int x, unsigned int y, const ColourOffset& err) +{ + // NB: We're storing the propagated error for both the current and the next + // line in a single-line buffer, using the following scheme upon entering + // this function: + // + // | Offset to x |-1 | 0 | 1 | 2 | 3 | + // |----------------|---|---|---|---|---| + // | Current row | | |(B)| B | B | + // | Next row | B | B | | | | + // + // and the following scheme upon leaving this function: + // + // | Offset to x |-1 | 0 | 1 | 2 | 3 | + // |----------------|---|---|---|---|---| + // | Current row | | |( )| B | B | + // | Next row | B | B | B | | | + // + // where "()" marks the current pixel, and "B" indicates that the error is + // stored in the buffer at the corresponding offset. Empty cells indicate + // that the corresponding error is not stored anywhere. + + maErr[x+2] += err * (2/4.0); // pixel to the right + maErr[x] += err * (1/4.0); // pixel below left + maErr[x+1] = err * (1/4.0); // pixel below (overwritten instead of added to) +} + +//******************************************************************************* + +FloydSteinbergDither::FloydSteinbergDither(unsigned int width) : + imageWidth(width), + maErr(new ColourOffset[width+2]) +{} + +FloydSteinbergDither::~FloydSteinbergDither() +{ + delete[] maErr; +} + +void FloydSteinbergDither::GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) +{ + if (x == 0) + mErrX.clear(); + offLin = maErr[x+1]; + offQnt.clear(); +} + +void FloydSteinbergDither::SetError(unsigned int x, unsigned int y, const ColourOffset& err) +{ + // NB: We're storing the propagated error for both the current and the next + // line in a single-line buffer, using the following scheme upon entering + // this function: + // + // | Offset to x |-1 | 0 | 1 | 2 | 3 | + // |----------------|---|---|---|---|---| + // | Current row | | |(B)| B | B | + // | Next row | B | B | X | | | + // + // and the following scheme upon leaving this function: + // + // | Offset to x |-1 | 0 | 1 | 2 | 3 | + // |----------------|---|---|---|---|---| + // | Current row | | |( )| B | B | + // | Next row | B | B | B | X | | + // + // where "()" marks the current pixel, "B" indicates that the error is + // stored in the buffer at the corresponding offset, and "X" indicates that + // the error is stored in `mErrX`. Empty cells indicate that the + // corresponding error is not stored anywhere. + + maErr[x+1] = mErrX; + maErr[x+2] += err * (7/16.0); // pixel to the right + maErr[x] += err * (3/16.0); // pixel below left + maErr[x+1] += err * (5/16.0); // pixel below + mErrX = err * (1/16.0); // pixel below right (overwritten instead of added to) +} + +//******************************************************************************* + +class DiffusionDither::Filter +{ +public: + Filter(std::initializer_list> raw, int drop = 0); + ~Filter(); + inline int Rows() const { return mRows; } + inline int Cols() const { return mCols; } + inline int ColX() const { return mColX; } + inline const ColourChannel& operator[](unsigned int i) const { return maData[i]; } +private: + unsigned int mRows; + unsigned int mCols; + unsigned int mColX; + ColourChannel* maData; +}; + +DiffusionDither::Filter::Filter(std::initializer_list> raw, int drop) : + mRows(raw.size()), + mCols((raw.end() - 1)->size()), + mColX(mCols - raw.begin()->size() - 1), + maData(new ColourChannel[mRows * mCols - mColX - 1]) +{ + POV_ASSERT(mRows > 0); + for (auto&& rawRow : raw) + POV_ASSERT((&rawRow == raw.begin()) || (rawRow.size() == mCols)); + + int sum = drop; + for (auto&& rawRow : raw) + for (auto&& rawCoeff : rawRow) + sum += rawCoeff; + POV_ASSERT(sum > 0); + ColourChannel invSum = 1.0 / sum; + ColourChannel* pCoeff = maData; + for (auto&& rawRow : raw) + for (auto&& rawCoeff : rawRow) + *(pCoeff++) = ColourChannel(rawCoeff) * invSum; +} + +DiffusionDither::Filter::~Filter() +{ + if (maData != nullptr) + delete[] maData; +} + +//------------------------------------------------------------------------------ + +DiffusionDither::DiffusionDither(const Filter& matrix, unsigned int width) : + mMatrix(matrix), + mImageWidth(width), + maaErrorBuffer(new ColourOffset*[matrix.Rows()]) +{ + for (unsigned int i = 0; i < matrix.Rows(); ++i) + maaErrorBuffer[i] = new ColourOffset[width + matrix.Cols() - 1]; +} + +DiffusionDither::~DiffusionDither() +{ + for (unsigned int i = 0; i < mMatrix.Rows(); ++i) + delete[] maaErrorBuffer[i]; + delete[] maaErrorBuffer; +} + +void DiffusionDither::GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) +{ + if (x == 0) + { + ColourOffset* tmp = maaErrorBuffer[0]; + for (unsigned int i = 1; i < mMatrix.Rows(); ++i) + maaErrorBuffer[i - 1] = maaErrorBuffer[i]; + maaErrorBuffer[mMatrix.Rows() - 1] = tmp; + for (unsigned int i = 0; i < mImageWidth + mMatrix.Cols() - 1; ++i) + maaErrorBuffer[mMatrix.Rows() - 1][i].clear(); + } + offLin = maaErrorBuffer[0][x + mMatrix.ColX()]; + offQnt.clear(); +} + +void DiffusionDither::SetError(unsigned int x, unsigned int y, const ColourOffset& err) +{ + unsigned int im = 0; + for (unsigned int iy = 0; iy < mMatrix.Rows(); ++iy) + for (unsigned int ix = (iy == 0 ? mMatrix.ColX() + 1 : 0); ix < mMatrix.Cols(); ++ix) + maaErrorBuffer[iy][x + ix] += err * mMatrix[im++]; +} + +//------------------------------------------------------------------------------- + +extern const OrderedDither::Pattern BayerMatrix2({ + { 0, 2 }, + { 3, 1 }}); + +extern const OrderedDither::Pattern BayerMatrix3({ + { 0, 3, 6 }, + { 7, 1, 4 }, + { 5, 8, 2 }}); + +extern const OrderedDither::Pattern BayerMatrix4({ + { 0, 8, 2, 10 }, + { 12, 4, 14, 6 }, + { 3, 11, 1, 9 }, + { 15, 7, 13, 5 }}); + +extern const OrderedDither::Pattern BlueNoise64a(64, kBlueNoise64a, 64 * 64); + +//******************************************************************************* + +extern const DiffusionDither::Filter AtkinsonMatrix( + {{ 1, 1 }, + { 1, 1, 1, 0 }, + { 0, 1, 0, 0 }}, 2); + +extern const DiffusionDither::Filter BurkesMatrix( + {{ 8, 4 }, + { 2, 4, 8, 4, 2 }}); + +extern const DiffusionDither::Filter JarvisJudiceNinkeMatrix( + {{ 7, 5 }, + { 3, 5, 7, 5, 3 }, + { 1, 3, 5, 3, 1 }}); + +extern const DiffusionDither::Filter Sierra2Matrix( + {{ 4, 3 }, + { 1, 2, 3, 2, 1 }}); + +extern const DiffusionDither::Filter Sierra3Matrix( + {{ 5, 3 }, + { 2, 4, 5, 4, 2 }, + { 0, 2, 3, 2, 0 }}); + +extern const DiffusionDither::Filter StuckiMatrix( + {{ 8, 4 }, + { 2, 4, 8, 4, 2 }, + { 1, 2, 4, 2, 1 }}); + +//******************************************************************************* + +DitherStrategySPtr GetDitherStrategy(DitherMethodId method, unsigned int imageWidth) +{ + DitherStrategySPtr s; + switch (method) + { + case DitherMethodId::kNone: s = std::make_shared (); break; + case DitherMethodId::kDiffusion1D: s = std::make_shared (); break; + case DitherMethodId::kSierraLite: s = std::make_shared (imageWidth); break; + case DitherMethodId::kFloydSteinberg: s = std::make_shared (imageWidth); break; + case DitherMethodId::kBayer2x2: s = std::make_shared (BayerMatrix2, imageWidth); break; + case DitherMethodId::kBayer3x3: s = std::make_shared (BayerMatrix3, imageWidth); break; + case DitherMethodId::kBayer4x4: s = std::make_shared (BayerMatrix4, imageWidth); break; + case DitherMethodId::kBlueNoise: s = std::make_shared (BlueNoise64a, imageWidth); break; + case DitherMethodId::kBlueNoiseX: s = std::make_shared (BlueNoise64a, imageWidth, true); break; + case DitherMethodId::kAtkinson: s = std::make_shared (AtkinsonMatrix, imageWidth); break; + case DitherMethodId::kBurkes: s = std::make_shared (BurkesMatrix, imageWidth); break; + case DitherMethodId::kJarvisJudiceNinke:s = std::make_shared (JarvisJudiceNinkeMatrix, imageWidth);break; + case DitherMethodId::kSierra3: s = std::make_shared (Sierra3Matrix, imageWidth); break; + case DitherMethodId::kSierra2: s = std::make_shared (Sierra2Matrix, imageWidth); break; + case DitherMethodId::kStucki: s = std::make_shared (StuckiMatrix, imageWidth); break; + } + return s; +} + +DitherStrategySPtr GetNoOpDitherStrategy() +{ + return DitherStrategySPtr(new NoDither()); +} + +ColourChannel GetDitherOffset(unsigned int x, unsigned int y) +{ + return BlueNoise64a(x, y); +} + +} // end of namespace pov_base diff --git a/source/base/image/dither.h b/source/base/image/dither.h new file mode 100644 index 000000000..6939277c6 --- /dev/null +++ b/source/base/image/dither.h @@ -0,0 +1,386 @@ +//****************************************************************************** +/// +/// @file base/image/dither.h +/// +/// Declarations related to image dithering. +/// +/// @copyright +/// @parblock +/// +/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. +/// +/// POV-Ray is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as +/// published by the Free Software Foundation, either version 3 of the +/// License, or (at your option) any later version. +/// +/// POV-Ray is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program. If not, see . +/// +/// ---------------------------------------------------------------------------- +/// +/// POV-Ray is based on the popular DKB raytracer version 2.12. +/// DKBTrace was originally written by David K. Buck. +/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. +/// +/// @endparblock +/// +//****************************************************************************** + +#ifndef POVRAY_BASE_IMAGE_DITHER_H +#define POVRAY_BASE_IMAGE_DITHER_H + +// Module config header file must be the first file included within POV-Ray unit header files +#include "base/configbase.h" + +// POV-Ray header files (base module) +#include "base/types.h" +#include "base/colour.h" + +namespace pov_base +{ + +//############################################################################## +/// +/// @defgroup PovBaseImageEncoding Basic Colour Encoding and Decoding +/// @ingroup PovBaseImage +/// +/// @{ + +class Image; + +//***************************************************************************** +/// +/// @name Dithering +/// +/// The following types and functions provide dithering functionality. +/// +/// @{ + +enum class DitherMethodId +{ + kNone, + kDiffusion1D, + kSierraLite, + kFloydSteinberg, + kBayer2x2, + kBayer3x3, + kBayer4x4, + kBlueNoise, + kBlueNoiseX, + kAtkinson, + kBurkes, + kJarvisJudiceNinke, + kSierra2, + kSierra3, + kStucki, +}; + +/// Abstract class representing a dithering algorithm and state. +/// +/// @note +/// The interface is designed to be used in quantization of a single complete image, with the +/// image processed line by line and pixel by pixel, starting at (x=0,y=0). Failure to adhere +/// to this processing order may lead to undefined behaviour in stateful dithering algorithms. +/// +class DitherStrategy +{ + public: + + /// Represents an offset to a colour. + struct ColourOffset; + + virtual ~DitherStrategy() {} + + /// Queries a colour offset from the algorithm. + /// + /// This function computes an offset to be added to the colour of a given pixel, based on + /// the pixel location and/or the algorithm's state. + /// + /// @param[in] x X coordinate of the pixel (may or may not be relevant to the algorithm). + /// @param[in] y Y coordinate of the pixel (may or may not be relevant to the algorithm). + /// @param[out] offLin Linear offset to add before any encoding steps. + /// This is typically based on carried-over quantization errors from neighboring pixels, as + /// used in stateful dither algorithms. + /// @param[out] offQnt Offset to add right before quantization (even after scaling). + /// This is typically more or less random noise in the range [-0.5, 0.5], as used in + /// stateless dither algorithms. + /// + virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) = 0; + + /// Reports the actual quantization error to the algorithm. + /// + /// This function feeds back the actual quantization error to the algorithm, allowing a + /// stateful algorithm to update its state accordingly. + /// + /// @param[in] x X coordinate of the pixel (may or may not be relevant to the algorithm). + /// @param[in] y Y coordinate of the pixel (may or may not be relevant to the algorithm). + /// @param[in] err Linear quantization error (may or may not be relevant to the algorithm). + /// + virtual void SetError(unsigned int x, unsigned int y, const ColourOffset& err) {} +}; + +struct DitherStrategy::ColourOffset +{ + union { ColourChannel red, gray; }; + ColourChannel green, blue, alpha; + + inline ColourOffset() : red(0.0f), green(0.0f), blue(0.0f), alpha(0.0f) {} + inline ColourOffset(ColourChannel r, ColourChannel g, ColourChannel b, ColourChannel a) : red(r), green(g), blue(b), alpha(a) {} + inline void clear() { red = 0.0f; green = 0.0f; blue = 0.0f; alpha = 0.0f; } + inline void setAll(ColourChannel v) { red = v; green = v; blue = v; alpha = v; } + inline void setRGB(RGBColour& v) { red = v.red(); green = v.green(); blue = v.blue(); alpha = 0.0; } + inline RGBColour getRGB() { return RGBColour(red, green, blue); } + inline ColourOffset operator*(ColourChannel b) const { return ColourOffset(red*b, green*b, blue*b, alpha*b); } + inline ColourOffset operator+(const ColourOffset& b) const { return ColourOffset(red + b.red, green + b.green, blue + b.blue, alpha + b.alpha); } + inline ColourOffset& operator+=(const ColourOffset& b) { red += b.red; green += b.green; blue += b.blue; alpha += b.alpha; return *this; } +}; + +typedef shared_ptr DitherStrategySPtr; + +/// Factory function to get a dithering algorithm and state. +DitherStrategySPtr GetDitherStrategy(DitherMethodId method, unsigned int imageWidth); + +/// Factory function to get a no-op dithering algorithm. +DitherStrategySPtr GetNoOpDitherStrategy(); + +/// Function providing simple stateless dithering. +/// +/// This function is provided as a fallback from the @ref DitherStrategy mechanism to provide basic +/// dithering functionality in cases where stateful operation is impractical, such as the render +/// preview. +/// +/// The current implementation is based on blue noise dithering. +/// +/// @param[in] x Image x coordinate. +/// @param[in] y Image y coordinate. +/// @return Offset to add right before quantization (even after scaling). +/// +ColourChannel GetDitherOffset(unsigned int x, unsigned int y); + +//------------------------------------------------------------------------------- + +/// "no-op" dithering strategy. +/// +/// This stateless dithering strategy serves as a placeholder when dithering +/// is not desired. +/// +class NoDither : public DitherStrategy +{ +public: + virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) override; +}; + +//------------------------------------------------------------------------------- + +/// Generalized ordered dithering strategy. +/// +/// This stateless dithering strategy implements a generalized ordered +/// dithering filter. The specifics of the filter are defined by a matrix. +/// +class OrderedDither : public DitherStrategy +{ +public: + class Pattern; + OrderedDither(const Pattern& matrix, unsigned int width, bool invertRB = false); + virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) override; +protected: + const Pattern& mPattern; + unsigned int mImageWidth; + bool mInvertRB; +}; + +/// 2x2 Bayer ordered dithering matrix. +/// +/// This matrix is based on principles proposed by B.E. Bayer in 1973. +/// +extern const OrderedDither::Pattern BayerMatrix2; + +/// 3x3 ordered dithering matrix. +/// +extern const OrderedDither::Pattern BayerMatrix3; + +/// 4x4 Bayer ordered dithering matrix. +/// +/// This matrix is based on principles proposed by B.E. Bayer in 1973. +/// +extern const OrderedDither::Pattern BayerMatrix4; + +/// 64x64 blue noise dithering matrix. +/// +/// This matrix was generated using the void-and-cluster method proposed by +/// R. Ulichney in 1993. +/// +extern const OrderedDither::Pattern BlueNoise64a; + +//------------------------------------------------------------------------------- + +/// Simple 1D error diffusion dithering strategy. +/// +/// This stateful dithering strategy implements the simplest error diffusion +/// dithering filter possible, propagating all of the quantization error to the +/// next pixel. +/// +/// This dithering strategy is equivalent to the following @ref DiffusionDither::Filter: +/// +/// DiffusionDither::Filter( +/// {{ 1 }}); +/// +class DiffusionDither1D : public DitherStrategy +{ +public: + virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) override; + virtual void SetError(unsigned int x, unsigned int y, const ColourOffset& err) override; +protected: + ColourOffset lastErr; +}; + +//------------------------------------------------------------------------------- + +/// Sierra Lite error diffusion dithering strategy. +/// +/// This stateful dithering strategy implements the error diffusion dithering +/// filter proposed by F. Sierra in 1990 as "Filter Lite" (aka "Sierra Lite" +/// or "Sierra-2-4A"), distributing the quantization error non-uniformly between +/// the pixel on the right and the pixels to the bottom left and straight below. +/// +/// @note This implementation uses an additional 1-line pixel buffer to avoid manipulating the original image. +/// +/// This dithering strategy is equivalent to the following @ref DiffusionDither::Filter: +/// +/// DiffusionDither::Filter( +/// {{ 2 }, +/// { 1, 1, 0 }}); +/// +class SierraLiteDither : public DitherStrategy +{ +public: + SierraLiteDither(unsigned int width); + virtual ~SierraLiteDither(); + virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) override; + virtual void SetError(unsigned int x, unsigned int y, const ColourOffset& err) override; +protected: + unsigned int imageWidth; + ColourOffset* maErr; +}; + +//------------------------------------------------------------------------------- + +/// Floyd-Steinberg error diffusion dithering strategy. +/// +/// This stateful dithering strategy implements the error diffusion dithering +/// filter proposed by R.W. Floyd and L. Steinberg in 1976. +/// +/// The Floyd-Steinberg filter distributes the error non-uniformly among the +/// pixel on the right as well as the three pixels below. +/// +/// @note This implementation uses an additional 1-line pixel buffer to avoid manipulating the original image. +/// +/// This dithering strategy is equivalent to the following @ref DiffusionDither::Filter: +/// +/// DiffusionDither::Filter( +/// {{ 7 }, +/// { 3, 5, 1 }}); +/// +class FloydSteinbergDither : public DitherStrategy +{ +public: + FloydSteinbergDither(unsigned int width); + virtual ~FloydSteinbergDither(); + virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) override; + virtual void SetError(unsigned int x, unsigned int y, const ColourOffset& err) override; +protected: + unsigned int imageWidth; + ColourOffset* maErr; + ColourOffset mErrX; +}; + +//------------------------------------------------------------------------------- + +/// Generalized error diffusion dithering strategy. +/// +/// This stateful dithering strategy implements a generalized error diffusion +/// dithering filter. The specifics of the filter are defined by a matrix. +/// +/// @note This implementation uses an additional multi-line pixel buffer to avoid manipulating the original image. +/// +class DiffusionDither : public DitherStrategy +{ +public: + class Filter; + DiffusionDither(const Filter& matrix, unsigned int width); + virtual ~DiffusionDither(); + virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) override; + virtual void SetError(unsigned int x, unsigned int y, const ColourOffset& err) override; +protected: + const Filter& mMatrix; + unsigned int mImageWidth; + ColourOffset** maaErrorBuffer; +}; + +/// Atkinson error diffusion dithering matrix. +/// +/// This matrix corresponds to the filter originally implemented by B. Atkinson +/// in Apple's HyperScan software. +/// +/// @note This filter propagates only 75% of the quantization error. +/// +extern const DiffusionDither::Filter AtkinsonMatrix; + +/// Burkes error diffusion dithering matrix. +/// +/// This matrix corresponds to the filter proposed by D. Burkes in 1988, +/// distributing the quantization error across five pixel columns and three +/// pixel rows. +/// +extern const DiffusionDither::Filter BurkesMatrix; + +/// Jarvis-Judice-Ninke error diffusion dithering matrix. +/// +/// This matrix corresponds to the filter proposed by J.F. Jarvis, C.N.Judice +/// and W.H. Ninke in 1976, distributing the quantization error across five +/// pixel columns and three pixel rows. +/// +extern const DiffusionDither::Filter JarvisJudiceNinkeMatrix; + +/// Two-Row Sierra error diffusion dithering matrix. +/// +/// This matrix corresponds to the filter proposed by F. Sierra in 1990 +/// (aka "Sierra-2"), distributing the quantization error across five pixel +/// columns and two pixel rows. +/// +extern const DiffusionDither::Filter Sierra2Matrix; + +/// Sierra error diffusion dithering matrix. +/// +/// This matrix corresponds to the filter proposed by F. Sierra in 1989 +/// (aka "Sierra-3"), distributing the quantization error across five pixel +/// columns and three pixel rows. +/// +extern const DiffusionDither::Filter Sierra3Matrix; + +/// Stucki error diffusion dithering matrix. +/// +/// This matrix corresponds to the filter proposed by P. Stucki in 1981, +/// distributing the quantization error across five pixel columns and three +/// pixel rows. +/// +extern const DiffusionDither::Filter StuckiMatrix; + +/// @} +/// +//***************************************************************************** + +/// @} +/// +//############################################################################## + +} // end of namespace pov_base + +#endif // POVRAY_BASE_IMAGE_DITHER_H diff --git a/source/base/image/encoding.cpp b/source/base/image/encoding.cpp index 3fd53bdb5..f751b67a5 100644 --- a/source/base/image/encoding.cpp +++ b/source/base/image/encoding.cpp @@ -9,7 +9,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,7 +37,8 @@ // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config) #include "base/image/encoding.h" -// POV-Ray base header files +// POV-Ray header files (base module) +#include "base/image/dither.h" #include "base/image/image.h" // this must be the last file included @@ -50,227 +51,6 @@ namespace pov_base #define ALPHA_EPSILON 1.0e-6 ///< Smallest alpha value we dare to safely use with premultiplied alpha. -static const unsigned int MaxBayerMatrixSize = 4; -typedef float BayerMatrix[MaxBayerMatrixSize][MaxBayerMatrixSize]; - -static const BayerMatrix BayerMatrices[MaxBayerMatrixSize+1] = -{ - // dummy for 0x0 - { { 0 } }, - // 1x1 (of little use, but here it is) - { { 1/2.0-0.5 } }, - // 2x2 - { { 1/4.0-0.5, 3/4.0-0.5 }, - { 4/4.0-0.5, 2/4.0-0.5 } }, - // 3x3 - { { 3/9.0-0.5, 7/9.0-0.5, 4/9.0-0.5 }, - { 6/9.0-0.5, 1/9.0-0.5, 9/9.0-0.5 }, - { 2/9.0-0.5, 8/9.0-0.5, 5/9.0-0.5 } }, - // 4x4 - { { 1/16.0-0.5, 9/16.0-0.5, 3/16.0-0.5, 11/16.0-0.5 }, - { 13/16.0-0.5, 5/16.0-0.5, 15/16.0-0.5, 7/16.0-0.5 }, - { 4/16.0-0.5, 12/16.0-0.5, 2/16.0-0.5, 10/16.0-0.5 }, - { 16/16.0-0.5, 8/16.0-0.5, 14/16.0-0.5, 6/16.0-0.5 } } -}; - -/*******************************************************************************/ - -/// Class representing "no-op" dithering rules. -class NoDither : public DitherStrategy -{ - public: - virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt); -}; - -/// Class representing bayer dithering rules, generating a regular pattern. -class BayerDither : public DitherStrategy -{ - public: - BayerDither(unsigned int mxSize); - virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt); - static inline float GetOffset(unsigned int x, unsigned int y, unsigned int ms) { return BayerMatrices[ms][x%ms][y%ms]; } - protected: - unsigned int matrixSize; -}; - -/// Class representing simple 1D error diffusion dithering rules, carrying over the error from one pixel to the next. -class DiffusionDither1D : public DitherStrategy -{ - public: - virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt); - virtual void SetError(unsigned int x, unsigned int y, const ColourOffset& err); - protected: - ColourOffset lastErr; -}; - -/// Class representing simple 2D error diffusion dithering rules, carrying over the error from one pixel to the right, as well as the two pixels below. -/// @note This implementation uses an additional 2-line pixel buffer to avoid manipulating the original image. -class DiffusionDither2D : public DitherStrategy -{ - public: - DiffusionDither2D(unsigned int width); - virtual ~DiffusionDither2D(); - virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt); - virtual void SetError(unsigned int x, unsigned int y, const ColourOffset& err); - protected: - unsigned int imageWidth; - ColourOffset* nextRowOffset; - ColourOffset* thisRowOffset; -}; - -/// Class representing Floyd-Steinberg dithering rules, carrying over the error from one pixel to the right, as well as the three pixels below. -/// @note This implementation uses an additional 2-line pixel buffer to avoid manipulating the original image. -class FloydSteinbergDither : public DitherStrategy -{ - public: - FloydSteinbergDither(unsigned int width); - virtual ~FloydSteinbergDither(); - virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt); - virtual void SetError(unsigned int x, unsigned int y, const ColourOffset& err); - protected: - unsigned int imageWidth; - ColourOffset* nextRowOffset; - ColourOffset* thisRowOffset; -}; - -/*******************************************************************************/ - -void NoDither::GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) -{ - offLin.clear(); - offQnt.clear(); -} - -/*******************************************************************************/ - -BayerDither::BayerDither(unsigned int mxSize) : - matrixSize(min(mxSize,MaxBayerMatrixSize)) -{ - ; -} - -void BayerDither::GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) -{ - offLin.clear(); - offQnt.setAll(GetOffset(x, y, matrixSize)); -} - -/*******************************************************************************/ - -void DiffusionDither1D::GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) -{ - offLin = lastErr; lastErr.clear(); offQnt.clear(); -} - -void DiffusionDither1D::SetError(unsigned int x, unsigned int y, const ColourOffset& err) -{ - lastErr = err; -} - -/*******************************************************************************/ - -DiffusionDither2D::DiffusionDither2D(unsigned int width) : - imageWidth(width), - thisRowOffset(new ColourOffset[width+1]), - nextRowOffset(new ColourOffset[width+1]) -{ - ; -} - -DiffusionDither2D::~DiffusionDither2D() -{ - delete[] thisRowOffset; - delete[] nextRowOffset; -} - -void DiffusionDither2D::GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) -{ - offLin = thisRowOffset[x]; - offQnt.clear(); -} - -void DiffusionDither2D::SetError(unsigned int x, unsigned int y, const ColourOffset& err) -{ - if (x == 0) - { - ColourOffset* tmp = nextRowOffset; - nextRowOffset = thisRowOffset; - thisRowOffset = tmp; - for (unsigned int i = 0; i < imageWidth+1; i ++) - nextRowOffset[i].clear(); - } - thisRowOffset[x+1] += err * (2/4.0); // pixel to the right - nextRowOffset[x] += err * (1/4.0); // pixel below - nextRowOffset[x+1] += err * (1/4.0); // pixel below right -} - -/*******************************************************************************/ - -FloydSteinbergDither::FloydSteinbergDither(unsigned int width) : - imageWidth(width), - thisRowOffset(new ColourOffset[width+2]), - nextRowOffset(new ColourOffset[width+2]) -{ - ; -} - -FloydSteinbergDither::~FloydSteinbergDither() -{ - delete[] thisRowOffset; - delete[] nextRowOffset; -} - -void FloydSteinbergDither::GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) -{ - offLin = thisRowOffset[x+1]; - offQnt.clear(); -} - -void FloydSteinbergDither::SetError(unsigned int x, unsigned int y, const ColourOffset& err) -{ - if (x == 0) - { - ColourOffset* tmp = nextRowOffset; - nextRowOffset = thisRowOffset; - thisRowOffset = tmp; - for (unsigned int i = 0; i < imageWidth+2; i ++) - nextRowOffset[i].clear(); - } - thisRowOffset[x+2] += err * (7/16.0); // pixel to the right - nextRowOffset[x] += err * (3/16.0); // pixel below left - nextRowOffset[x+1] += err * (5/16.0); // pixel below - nextRowOffset[x+2] += err * (1/16.0); // pixel below right -} - -/*******************************************************************************/ - -DitherStrategySPtr GetDitherStrategy(DitherMethodId method, unsigned int imageWidth) -{ - switch (method) - { - case kPOVList_DitherMethod_None: return DitherStrategySPtr(new NoDither()); - case kPOVList_DitherMethod_Diffusion1D: return DitherStrategySPtr(new DiffusionDither1D()); - case kPOVList_DitherMethod_Diffusion2D: return DitherStrategySPtr(new DiffusionDither2D(imageWidth)); - case kPOVList_DitherMethod_FloydSteinberg: return DitherStrategySPtr(new FloydSteinbergDither(imageWidth)); - case kPOVList_DitherMethod_Bayer2x2: return DitherStrategySPtr(new BayerDither(2)); - case kPOVList_DitherMethod_Bayer3x3: return DitherStrategySPtr(new BayerDither(3)); - case kPOVList_DitherMethod_Bayer4x4: return DitherStrategySPtr(new BayerDither(4)); - default: throw POV_EXCEPTION_STRING("Invalid dither method for output"); - } -} - -DitherStrategySPtr GetNoOpDitherStrategy() -{ - return DitherStrategySPtr(new NoDither()); -} - -/*******************************************************************************/ - -float GetDitherOffset(unsigned int x, unsigned int y) -{ - return BayerDither::GetOffset(x,y,4); -} - /*******************************************************************************/ inline void AlphaPremultiply(float& fGray, float fAlpha) @@ -443,7 +223,7 @@ unsigned int GetEncodedGrayValue(const Image* img, unsigned int x, unsigned int } DitherStrategy::ColourOffset linOff, encOff; dh.GetOffset(x,y,linOff,encOff); - unsigned int iGray = IntEncode(g,fGray+linOff.gray,max,encOff.gray,linOff.gray); + unsigned int iGray = IntEncode(g, fGray, max, encOff.gray, linOff.gray); dh.SetError(x,y,linOff); return iGray; } @@ -488,8 +268,8 @@ void GetEncodedGrayAValue(const Image* img, unsigned int x, unsigned int y, cons // else no need to worry about premultiplication DitherStrategy::ColourOffset linOff, encOff; dh.GetOffset(x,y,linOff,encOff); - gray = IntEncode(g, fGray + linOff.gray, max, encOff.gray, linOff.gray); - alpha = IntEncode(fAlpha + linOff.alpha, max, encOff.alpha, linOff.alpha); + gray = IntEncode(g, fGray, max, encOff.gray, linOff.gray); + alpha = IntEncode( fAlpha, max, encOff.alpha, linOff.alpha); dh.SetError(x,y,linOff); } void GetEncodedRGBValue(const Image* img, unsigned int x, unsigned int y, const GammaCurvePtr& g, unsigned int max, unsigned int& red, unsigned int& green, unsigned int& blue, DitherStrategy& dh) @@ -509,9 +289,9 @@ void GetEncodedRGBValue(const Image* img, unsigned int x, unsigned int y, const } DitherStrategy::ColourOffset linOff, encOff; dh.GetOffset(x,y,linOff,encOff); - red = IntEncode(g,fRed + linOff.red, max, encOff.red, linOff.red); - green = IntEncode(g,fGreen + linOff.green, max, encOff.green, linOff.green); - blue = IntEncode(g,fBlue + linOff.blue, max, encOff.blue, linOff.blue); + red = IntEncode(g, fRed, max, encOff.red, linOff.red); + green = IntEncode(g, fGreen, max, encOff.green, linOff.green); + blue = IntEncode(g, fBlue, max, encOff.blue, linOff.blue); dh.SetError(x,y,linOff); } void GetEncodedRGBAValue(const Image* img, unsigned int x, unsigned int y, const GammaCurvePtr& g, unsigned int max, unsigned int& red, unsigned int& green, unsigned int& blue, unsigned int& alpha, DitherStrategy& dh, bool premul) @@ -562,10 +342,10 @@ void GetEncodedRGBAValue(const Image* img, unsigned int x, unsigned int y, const // else no need to worry about premultiplication DitherStrategy::ColourOffset linOff, encOff; dh.GetOffset(x,y,linOff,encOff); - red = IntEncode(g,fRed + linOff.red, max, encOff.red, linOff.red); - green = IntEncode(g,fGreen + linOff.green, max, encOff.green, linOff.green); - blue = IntEncode(g,fBlue + linOff.blue, max, encOff.blue, linOff.blue); - alpha = IntEncode(fAlpha + linOff.alpha, max, encOff.alpha, linOff.alpha); + red = IntEncode(g, fRed, max, encOff.red, linOff.red); + green = IntEncode(g, fGreen, max, encOff.green, linOff.green); + blue = IntEncode(g, fBlue, max, encOff.blue, linOff.blue); + alpha = IntEncode( fAlpha, max, encOff.alpha, linOff.alpha); dh.SetError(x,y,linOff); } diff --git a/source/base/image/encoding.h b/source/base/image/encoding.h index ea9a39ff6..f4e444efd 100644 --- a/source/base/image/encoding.h +++ b/source/base/image/encoding.h @@ -9,7 +9,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -48,6 +48,9 @@ namespace pov_base { +class DitherStrategy; +class Image; + //############################################################################## /// /// @defgroup PovBaseImageEncoding Basic Colour Encoding and Decoding @@ -55,107 +58,6 @@ namespace pov_base /// /// @{ -class Image; - -enum DitherMethodId -{ - kPOVList_DitherMethod_None, - kPOVList_DitherMethod_Diffusion1D, - kPOVList_DitherMethod_Diffusion2D, - kPOVList_DitherMethod_FloydSteinberg, - kPOVList_DitherMethod_Bayer2x2, - kPOVList_DitherMethod_Bayer3x3, - kPOVList_DitherMethod_Bayer4x4, -}; - -/// Abstract class representing a dithering algorithm and state. -/// -/// @note -/// The interface is designed to be used in quantization of a single complete image, with the -/// image processed line by line and pixel by pixel, starting at (x=0,y=0). Failure to adhere -/// to this processing order may lead to undefined behaviour in stateful dithering algorithms. -/// -class DitherStrategy -{ - public: - - /// Represents an offset to a colour. - struct ColourOffset - { - union { float red, gray; }; float green, blue, alpha; - ColourOffset() : red(0.0f), green(0.0f), blue(0.0f), alpha(0.0f) { } - ColourOffset(float r, float g, float b, float a) : red(r), green(g), blue(b), alpha(a) { } - void clear() { red = 0.0f; green = 0.0f; blue = 0.0f; alpha = 0.0f; } - void setAll(float v) { red = v; green = v; blue = v; alpha = v; } - void setRGB(RGBColour& v) { red = v.red(); green = v.green(); blue = v.blue(); alpha = 0.0; } - RGBColour getRGB() { return RGBColour(red, green, blue); } - ColourOffset operator*(float b) const { return ColourOffset(red*b, green*b, blue*b, alpha*b); } - ColourOffset operator+(const ColourOffset& b) const { return ColourOffset(red+b.red, green+b.green, blue+b.blue, alpha+b.alpha); } - void operator+=(const ColourOffset& b) { red+=b.red; green+=b.green; blue+=b.blue; alpha+=b.alpha; } - }; - - virtual ~DitherStrategy() {} - - /// Queries a colour offset from the algorithm. - /// - /// This function computes an offset to be added to the colour of a given pixel, based on - /// the pixel location and/or the algorithm's state. - /// - /// @param[in] x X coordinate of the pixel (may or may not be relevant to the algorithm). - /// @param[in] y Y coordinate of the pixel (may or may not be relevant to the algorithm). - /// @param[out] offLin Linear offset to add before any encoding steps. - /// This is typically based on carried-over quantization errors from neighboring pixels, as - /// used in stateful dither algorithms. - /// @param[out] offQnt Offset to add right before quantization (even after scaling). - /// This is typically more or less random noise in the range [-0.5, 0.5], as used in - /// stateless dither algorithms. - /// - virtual void GetOffset(unsigned int x, unsigned int y, ColourOffset& offLin, ColourOffset& offQnt) = 0; - - /// Reports the actual quantization error to the algorithm. - /// - /// This function feeds back the actual quantization error to the algorithm, allowing a - /// stateful algorithm to update its state accordingly. - /// - /// @param[in] x X coordinate of the pixel (may or may not be relevant to the algorithm). - /// @param[in] y Y coordinate of the pixel (may or may not be relevant to the algorithm). - /// @param[in] err Linear quantization error (may or may not be relevant to the algorithm). - /// - virtual void SetError(unsigned int x, unsigned int y, const ColourOffset& err) {} -}; - -typedef shared_ptr DitherStrategySPtr; - -//***************************************************************************** -/// -/// @name Dithering -/// -/// The following functions provide dithering functionality. -/// -/// @{ - -/// Factory function to get a dithering algorithm and state. -DitherStrategySPtr GetDitherStrategy(DitherMethodId method, unsigned int imageWidth); - -/// Factory function to get a no-op dithering algorithm. -DitherStrategySPtr GetNoOpDitherStrategy(); - -/// Function providing simple stateless dithering. -/// -/// This function is provided as a fallback from the `DitherStrategy` mechanism to provide basic -/// dithering functionality in cases where stateful operation is impractical, such as the render -/// preview. -/// -/// The current implementation is based on 4x4 Bayer dithering. -/// -/// @param[in] x Image x coordinate. -/// @param[in] y Image y coordinate. -/// @return Offset to add right before quantization (even after scaling). -/// -float GetDitherOffset(unsigned int x, unsigned int y); - -/// @} -/// //***************************************************************************** /// /// @name Basic Decoding @@ -202,10 +104,28 @@ inline float IntDecode(const GammaCurvePtr& g, unsigned int x, unsigned int max) /// /// @{ -/// Linear encoding function. +/// Linear encoding function rounding down. /// /// This function maps a floating-point value in the range 0..1 linearly to an integer value -/// in the range 0..max. +/// in the range 0..max, rounding down. +/// +/// @note +/// Floating-point values outside the range 0..1 are clipped, mapping them to 0 or max, +/// respectively. +/// +/// @param[in] x Value to encode. +/// @param[in] max Encoded value representing 1.0. +/// @param[in] qOff Offset to add before quantization. +/// +inline unsigned int IntEncodeDown(float x, unsigned int max, float qOff = 0.0f) +{ + return (unsigned int)clip(floor(x * float(max) + qOff), 0.0f, float(max)); +} + +/// Linear encoding function rounding to nearest. +/// +/// This function maps a floating-point value in the range 0..1 linearly to an integer value +/// in the range 0..max, rounding to the nearest value. /// /// @note /// Floating-point values outside the range 0..1 are clipped, mapping them to 0 or max, @@ -217,7 +137,7 @@ inline float IntDecode(const GammaCurvePtr& g, unsigned int x, unsigned int max) /// inline unsigned int IntEncode(float x, unsigned int max, float qOff = 0.0f) { - return (unsigned int)clip(floor(x * float(max) + qOff + 0.5f), 0.0f, float(max)); + return IntEncodeDown(x, max, qOff + 0.5f); } /// Linear encoding function. @@ -232,12 +152,13 @@ inline unsigned int IntEncode(float x, unsigned int max, float qOff = 0.0f) /// @param[in] x Value to encode. /// @param[in] max Encoded value representing 1.0. /// @param[in] qOff Offset to add before quantization. -/// @param[out] err Quantization error (including effects due to adding qOff). +/// @param[in,out] err Quantization error (including effects due to adding qOff). /// inline unsigned int IntEncode(float x, unsigned int max, float qOff, float& err) { - unsigned int v = IntEncode(x, max, qOff); - err = clip(x, 0.0f, 1.0f) - IntDecode(v, max); + float xEff = clip(x, 0.0f, 1.0f) + err; + unsigned int v = IntEncode(xEff, max, qOff); + err = xEff - IntDecode(v, max); return v; } @@ -247,17 +168,39 @@ inline unsigned int IntEncode(float x, unsigned int max, float qOff, float& err) /// in the range 0..max. /// /// @note -/// Floating-point values outside the range 0..1 (after applying the transfer function) -/// are clipped, mapping them to 0 or max, respectively. +/// Floating-point values outside the range 0..1 are clipped, mapping them to 0 or max, +/// respectively. +/// @note +/// The transfer function is presumed to map values 0 and 1 to the respective value itself. /// /// @param[in] g Transfer function (gamma curve) to use. /// @param[in] x Value to encode. /// @param[in] max Encoded value representing 1.0. /// @param[in] qOff Offset to add before quantization. +/// @param[in,out] err Quantization error (including effects due to adding qOff). /// -inline unsigned int IntEncode(const GammaCurvePtr& g, float x, unsigned int max, float qOff = 0.0f) +inline unsigned int IntEncode(const GammaCurvePtr& g, float x, unsigned int max, float qOff, float& err) { - return IntEncode(GammaCurve::Encode(g, x), max, qOff); + if (GammaCurve::IsNeutral(g)) + return IntEncode(x, max, qOff, err); + + float xEff = clip(x, 0.0f, 1.0f) + err; + unsigned int v = IntEncodeDown(GammaCurve::Encode(g, xEff), max); + float decoded = IntDecode(g, v, max); + if (v >= max) + { + err = xEff - decoded; + return v; + } + float decodedUp = IntDecode(g, v + 1, max); + float threshold = (0.5 - qOff) * decoded + (0.5 + qOff) * decodedUp; + if (xEff > threshold) + { + decoded = decodedUp; + ++v; + } + err = xEff - decoded; + return v; } /// Generic encoding function. @@ -266,20 +209,20 @@ inline unsigned int IntEncode(const GammaCurvePtr& g, float x, unsigned int max, /// in the range 0..max. /// /// @note -/// Floating-point values outside the range 0..1 (after applying the transfer function) -/// are clipped, mapping them to 0 or max, respectively. +/// Floating-point values outside the range 0..1 are clipped, mapping them to 0 or max, +/// respectively. +/// @note +/// The transfer function is presumed to map values 0 and 1 to the respective value itself. /// /// @param[in] g Transfer function (gamma curve) to use. /// @param[in] x Value to encode. /// @param[in] max Encoded value representing 1.0. /// @param[in] qOff Offset to add before quantization. -/// @param[out] err Quantization error (including effects due to adding qOff). /// -inline unsigned int IntEncode(const GammaCurvePtr& g, float x, unsigned int max, float qOff, float& err) +inline unsigned int IntEncode(const GammaCurvePtr& g, float x, unsigned int max, float qOff = 0.0f) { - unsigned int v = IntEncode(g, x, max, qOff); - err = clip(x, 0.0f, 1.0f) - IntDecode(g, v, max); - return v; + float err = 0.0f; + return IntEncode(g, x, max, qOff, err); } /// @} diff --git a/source/base/image/hdr.cpp b/source/base/image/hdr.cpp index a5c489151..cc56c0047 100644 --- a/source/base/image/hdr.cpp +++ b/source/base/image/hdr.cpp @@ -42,15 +42,13 @@ #include "base/image/hdr.h" // Standard C++ header files +#include #include -// Boost header files -#include -#include - -// POV-Ray base header files +// POV-Ray header files (base module) #include "base/fileinputoutput.h" #include "base/types.h" +#include "base/image/dither.h" #include "base/image/metadata.h" // this must be the last file included @@ -210,7 +208,7 @@ Image *Read(IStream *file, const Image::ReadOptions& options) image = Image::Create(width, height, imagetype); // NB: HDR files don't use alpha, so premultiplied vs. non-premultiplied is not an issue - boost::scoped_array scanline(new unsigned char[4 * width]); + std::unique_ptr scanline(new unsigned char[4 * width]); for(int row = 0; row < height; row++) { // determine scanline type @@ -318,7 +316,7 @@ void Write(OStream *file, const Image *image, const Image::WriteOptions& options file->printf("\n"); file->printf("-Y %d +X %d\n", height, width); - boost::scoped_array scanline(new RGBE[width]); + std::unique_ptr scanline(new RGBE[width]); for(int row = 0; row < height; row++) { diff --git a/source/base/image/image.cpp b/source/base/image/image.cpp index 27a5dd2f1..4900187e8 100644 --- a/source/base/image/image.cpp +++ b/source/base/image/image.cpp @@ -45,10 +45,11 @@ #include #include -// POV-Ray base header files +// POV-Ray header files (base module) #include "base/platformbase.h" #include "base/safemath.h" #include "base/image/bmp.h" +#include "base/image/dither.h" #include "base/image/gif.h" #include "base/image/hdr.h" #include "base/image/iff.h" @@ -78,6 +79,16 @@ namespace pov_base using std::allocator; +Image::WriteOptions::WriteOptions() : + ditherStrategy(GetNoOpDitherStrategy()), + offset_x(0), + offset_y(0), + alphaMode(kAlphaMode_None), + bitsPerChannel(8), + compression(-1), + grayscale(false) +{} + template > class BitMapImage : public Image { diff --git a/source/base/image/image.h b/source/base/image/image.h index 3d4dc57f8..68b3d7cae 100644 --- a/source/base/image/image.h +++ b/source/base/image/image.h @@ -48,6 +48,9 @@ namespace pov_base { +class DitherStrategy; +using DitherStrategySPtr = shared_ptr; + //############################################################################## /// /// @defgroup PovBaseImage Image Handling @@ -287,15 +290,7 @@ class Image /// in POV-Ray. bool grayscale : 1; - WriteOptions() : - ditherStrategy(GetNoOpDitherStrategy()), - offset_x(0), - offset_y(0), - alphaMode(kAlphaMode_None), - bitsPerChannel(8), - compression(-1), - grayscale(false) - {} + WriteOptions(); inline bool AlphaIsEnabled() const { diff --git a/source/base/image/jpeg.cpp b/source/base/image/jpeg.cpp index c0d0e68b2..6f6aba002 100644 --- a/source/base/image/jpeg.cpp +++ b/source/base/image/jpeg.cpp @@ -44,7 +44,8 @@ #ifndef LIBJPEG_MISSING -#include +// C++ variants of standard C header files +#include // Standard C++ header files #include @@ -58,7 +59,8 @@ extern "C" #include } -// POV-Ray base header files +// POV-Ray header files (base module) +#include "base/image/dither.h" #include "base/image/metadata.h" // this must be the last file included @@ -89,7 +91,7 @@ class POV_JPEG_Write_Buffer struct jpeg_error_mgr jerr; jpeg_source_mgr jsrc; jpeg_destination_mgr jdest; - jmp_buf setjmp_buffer; // for return to caller + std::jmp_buf setjmp_buffer; // for return to caller char buffer[POV_JPEG_BUFFER_SIZE]; JSAMPROW row_pointer[1]; int row_stride; @@ -117,7 +119,7 @@ class POV_JPEG_Read_Buffer struct jpeg_error_mgr jerr; jpeg_source_mgr jsrc; jpeg_destination_mgr jdest; - jmp_buf setjmp_buffer; // for return to caller + std::jmp_buf setjmp_buffer; // for return to caller char buffer[POV_JPEG_BUFFER_SIZE]; JSAMPROW row_pointer[1]; int row_stride; @@ -159,7 +161,7 @@ extern "C" (*cinfo->err->output_message)(cinfo); // Return control to the setjmp point - longjmp(myerr->setjmp_buffer, 1); + std::longjmp(myerr->setjmp_buffer, 1); } METHODDEF(void) write_error_exit (j_common_ptr cinfo) @@ -169,7 +171,7 @@ extern "C" (*cinfo->err->output_message)(cinfo); // Return control to the setjmp point - longjmp(myerr->setjmp_buffer, 1); + std::longjmp(myerr->setjmp_buffer, 1); } METHODDEF(void) read_output_message(j_common_ptr cinfo) @@ -530,6 +532,6 @@ void Write (OStream *file, const Image *image, const Image::WriteOptions& option } // end of namespace Jpeg -} +} // end of namespace pov_base #endif // LIBJPEG_MISSING diff --git a/source/base/image/png.cpp b/source/base/image/png.cpp index a98617d15..98f38de0b 100644 --- a/source/base/image/png.cpp +++ b/source/base/image/png.cpp @@ -43,12 +43,11 @@ #ifndef LIBPNG_MISSING +// C++ standard headers #include +#include -// Boost header files -#include -#include - +// other 3rd party library headers #include // POV-Ray base header files @@ -666,23 +665,29 @@ Image *Read (IStream *file, const Image::ReadOptions& options) return (image) ; } +void SetChannelValue(png_bytep& p, unsigned int v, unsigned int bpcc) +{ + if (bpcc > 8) + *(p++) = ((v >> 8) & 0xFF); + *(p++) = (v & 0xFF); +} + void Write (OStream *file, const Image *image, const Image::WriteOptions& options) { - int himask; int png_stride; int width = image->GetWidth() ; int height = image->GetHeight() ; - int j; int bpcc = options.bitsPerChannel; bool use_alpha = image->HasTransparency() && options.AlphaIsEnabled(); - unsigned int color; + unsigned int octetDepth = ((bpcc + 7) / 8); + unsigned int bitDepth = 8 * octetDepth; unsigned int alpha; unsigned int r; unsigned int g; unsigned int b; unsigned int maxValue; - unsigned int hiShift; - unsigned int loShift; + unsigned int mult; + unsigned int shift; png_info *info_ptr = nullptr; png_struct *png_ptr = nullptr; Messages messages; @@ -697,17 +702,11 @@ void Write (OStream *file, const Image *image, const Image::WriteOptions& option // (e.g. to handle a non-compliant file). bool premul = options.AlphaIsPremultiplied(false); - if (bpcc == 0) + if (bpcc <= 0) bpcc = image->GetMaxIntValue() == 65535 ? 16 : 8 ; - else if (bpcc < 5) - bpcc = 5 ; else if (bpcc > 16) bpcc = 16 ; - // special case: if options.grayscale is set, we enforce 16bpp irregardless of other settings - if (options.grayscale) - bpcc = 16; - maxValue = (1< row_ptr(new png_byte[width*png_stride]); - boost::scoped_array row_ptr (new png_byte [width*png_stride]); + int repeat = (bitDepth + bpcc - 1) / bpcc; + shift = (bpcc * repeat) - bitDepth; + mult = 0x01; + for (int i = 1; i < repeat; ++i) + mult = (mult << bpcc) | 0x01; for (int row = 0 ; row < height ; row++) { - /* - * We must copy all the values because PNG expects RGBRGB bytes, but - * POV-Ray stores RGB components in separate arrays as floats. In - * order to use the full scale values at the lower bit depth, PNG - * recommends filling the low-order bits with a copy of the high-order - * bits. However, studies have shown that filling the low order bits - * with constant bits significantly improves compression, which we're - * doing here. Note that since the true bit depth is stored in the - * sBIT chunk, the extra packed bits are not important. - */ - - switch (bpcc) + auto p = row_ptr.get(); + for (int col = 0; col < width; ++col) { - case 5: - case 6: - case 7: - // Handle shifting for arbitrary output bit depth - hiShift = 8 - bpcc; - loShift = 2*bpcc - 8; - if (use_color) - { - for (int col = j = 0; col < width; col++, j += png_stride) - { - if (use_alpha) - { - GetEncodedRGBAValue (image, col, row, gamma, maxValue, r, g, b, alpha, dither, premul); - row_ptr[j + 3] = alpha << hiShift; - row_ptr[j + 3] |= alpha >> loShift; - } - else - GetEncodedRGBValue (image, col, row, gamma, maxValue, r, g, b, dither); - - row_ptr[j] = r << hiShift; - row_ptr[j] |= r >> loShift; - - row_ptr[j+1] = g << hiShift; - row_ptr[j+1] |= g >> loShift; - - row_ptr[j+2] = b << hiShift; - row_ptr[j+2] |= b >> loShift; - } - } - else - { - for (int col = j = 0; col < width; col++, j += png_stride) - { - if (use_alpha) - { - GetEncodedGrayAValue (image, col, row, gamma, maxValue, color, alpha, dither, premul); - row_ptr[j + 1] = alpha << hiShift; - row_ptr[j + 1] |= alpha >> loShift; - } - else - color = GetEncodedGrayValue (image, col, row, gamma, maxValue, dither) ; - - // Use left-bit replication (LBR) for bit depths < 8 - row_ptr[j] = color << hiShift; - row_ptr[j] |= color >> loShift; - } - } - break; - - case 8: - if (use_color) - { - for (int col = j = 0; col < width; col++, j += png_stride) - { - if (use_alpha) - { - GetEncodedRGBAValue (image, col, row, gamma, maxValue, r, g, b, alpha, dither, premul); - row_ptr[j + 3] = alpha; - } - else - GetEncodedRGBValue (image, col, row, gamma, maxValue, r, g, b, dither) ; - row_ptr[j] = r; - row_ptr[j + 1] = g; - row_ptr[j + 2] = b; - } - } - else - { - for (int col = j = 0; col < width; col++, j += png_stride) - { - if (use_alpha) - { - GetEncodedGrayAValue (image, col, row, gamma, maxValue, color, alpha, dither, premul); - row_ptr[j + 1] = alpha; - } - else - color = GetEncodedGrayValue (image, col, row, gamma, maxValue, dither) ; - row_ptr[j] = color; - } - } - break; - - case 16: - if (use_color) - { - for (int col = j = 0; col < width; col++, j += png_stride) - { - if (use_alpha) - { - GetEncodedRGBAValue (image, col, row, gamma, maxValue, r, g, b, alpha, dither, premul); - row_ptr[j+6] = alpha >> 8; - row_ptr[j+7] = alpha & 0xff; - } - else - GetEncodedRGBValue (image, col, row, gamma, maxValue, r, g, b, dither) ; - - row_ptr[j] = r >> 8; - row_ptr[j + 1] = r & 0xFF; - - row_ptr[j + 2] = g >> 8; - row_ptr[j + 3] = g & 0xFF; - - row_ptr[j + 4] = b >> 8; - row_ptr[j + 5] = b & 0xFF; - } - } - else - { - for (int col = j = 0; col < width; col++, j += png_stride) - { - if (use_alpha) - { - GetEncodedGrayAValue (image, col, row, gamma, maxValue, color, alpha, dither, premul); - row_ptr[j+2] = alpha >> 8; - row_ptr[j+3] = alpha & 0xff; - } - else - color = GetEncodedGrayValue (image, col, row, gamma, maxValue, dither) ; - row_ptr[j] = color >> 8; - row_ptr[j+1] = color & 0xff; - } - } - break; - - default: // bpcc 9 - 15 - // Handle shifting for arbitrary output bit depth - hiShift = 16 - bpcc; - loShift = 2*bpcc - 16; - himask = 0xFF ^ ((1 << hiShift) - 1); - if (use_color) - { - for (int col = j = 0; col < width; col++, j += png_stride) - { - if (use_alpha) - { - GetEncodedRGBAValue (image, col, row, gamma, maxValue, r, g, b, alpha, dither, premul); - row_ptr[j + 6] = alpha >> (8 - hiShift); - row_ptr[j + 7] = alpha << hiShift; - row_ptr[j + 7] |= alpha >> loShift; - } - else - GetEncodedRGBValue (image, col, row, gamma, maxValue, r, g, b, dither) ; - - row_ptr[j] = r >> (8 - hiShift); - row_ptr[j + 1] = r << hiShift; - row_ptr[j + 1] |= r >> loShift; - - row_ptr[j + 2] = g >> (8 - hiShift); - row_ptr[j + 3] = g << hiShift; - row_ptr[j + 3] |= g >> loShift; + if (use_color && use_alpha) + GetEncodedRGBAValue(image, col, row, gamma, maxValue, r, g, b, alpha, dither, premul); + else if (use_color) + GetEncodedRGBValue(image, col, row, gamma, maxValue, r, g, b, dither); + else if (use_alpha) + GetEncodedGrayAValue(image, col, row, gamma, maxValue, g, alpha, dither, premul); + else + g = GetEncodedGrayValue(image, col, row, gamma, maxValue, dither); - row_ptr[j + 4] = b >> (8 - hiShift); - row_ptr[j + 5] = b << hiShift; - row_ptr[j + 5] |= b >> loShift; - } - } - else - { - for (int col = j = 0; col < width; col++, j += png_stride) - { - if (use_alpha) - { - GetEncodedGrayAValue (image, col, row, gamma, maxValue, color, alpha, dither, premul); - row_ptr[j + 2] = alpha >> (8 - hiShift); - row_ptr[j + 3] = alpha << hiShift; - row_ptr[j + 3] |= alpha >> loShift; - } - else - color = GetEncodedGrayValue (image, col, row, gamma, maxValue, dither) ; + if (use_color) + { + SetChannelValue(p, (r * mult) >> shift, bpcc); + SetChannelValue(p, (g * mult) >> shift, bpcc); + SetChannelValue(p, (b * mult) >> shift, bpcc); + } + else + { + SetChannelValue(p, (g * mult) >> shift, bpcc); + } - row_ptr[j] = color >> (8 - hiShift); - row_ptr[j + 1] = color << hiShift; - row_ptr[j + 1] |= color >> loShift; - } - } + if (use_alpha) + SetChannelValue(p, (alpha * mult) >> shift, bpcc); } if (setjmp(png_jmpbuf(png_ptr))) @@ -1015,6 +857,6 @@ void Write (OStream *file, const Image *image, const Image::WriteOptions& option } // end of namespace Png -} +} // end of namespace pov_base #endif // LIBPNG_MISSING diff --git a/source/base/image/ppm.cpp b/source/base/image/ppm.cpp index f8fa357c2..6a16efa98 100644 --- a/source/base/image/ppm.cpp +++ b/source/base/image/ppm.cpp @@ -9,7 +9,7 @@ /// according to Netpbm specs (http://netpbm.sourceforge.net/doc/): /// /// For input, both ASCII ("plain") and binary ("raw") formats (magic numbers -/// `P2`/`P3` and `P5`/`P6`, respectively), are supported. +/// `P2`/`P3` and `P5`/`P6`, respectively) are supported. /// /// For outout we write binary ("raw") PPM files (magic number `P6`), unless /// `Greyscale_Output=on` is specified in which case we write binary PGM files @@ -104,10 +104,8 @@ void Write (OStream *file, const Image *image, const Image::WriteOptions& option plainFormat = (options.compression == 0); #endif - if (bpcc == 0) + if (bpcc <= 0) bpcc = image->GetMaxIntValue() == 65535 ? 16 : 8 ; - else if (bpcc < 5) - bpcc = 5 ; else if (bpcc > 16) bpcc = 16 ; @@ -115,11 +113,9 @@ void Write (OStream *file, const Image *image, const Image::WriteOptions& option // do we want 16 bit grayscale (PGM) output ? // TODO - the check for image container type is here to mimick old code; do we still need it? - if (image->GetImageDataType () == Image::Gray_Int16 || image->GetImageDataType () == Image::GrayA_Int16 || options.grayscale) + if (image->IsGrayscale() || options.grayscale) { - grayscale = true; - bpcc = 16; - gamma.reset(); // TODO - this is here to mimick old code, which never did gamma correction for greyscale output; do we want to change that? + grayscale = true; if (plainFormat) file->printf("P2\n"); else @@ -400,5 +396,5 @@ Image *Read (IStream *file, const Image::ReadOptions& options) } // end of namespace Netpbm -} +} // end of namespace pov_base diff --git a/source/frontend/display.cpp b/source/frontend/display.cpp index 749e7105c..865baa293 100644 --- a/source/frontend/display.cpp +++ b/source/frontend/display.cpp @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -42,10 +42,9 @@ namespace pov_frontend { -Display::Display(unsigned int w, unsigned int h, pov_base::GammaCurvePtr g) : +Display::Display(unsigned int w, unsigned int h) : width(w), - height(h), - gamma(g) + height(h) { // nothing to do } @@ -65,11 +64,6 @@ unsigned int Display::GetHeight() return height; } -pov_base::GammaCurvePtr Display::GetGamma() -{ - return pov_base::GammaCurvePtr(gamma); -} - void Display::DrawRectangleFrame(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, const RGBA8& colour) { for(unsigned int x = x1; x <= x2; x++) diff --git a/source/frontend/display.h b/source/frontend/display.h index 0ae00f4a5..71c9a403b 100644 --- a/source/frontend/display.h +++ b/source/frontend/display.h @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -39,8 +39,6 @@ // Module config header file must be the first file included within POV-Ray unit header files #include "frontend/configfrontend.h" -#include "base/image/colourspace.h" - namespace pov_frontend { @@ -49,7 +47,7 @@ class Display public: struct RGBA8 { unsigned char red, green, blue, alpha; }; - Display(unsigned int w, unsigned int h, pov_base::GammaCurvePtr g); + Display(unsigned int w, unsigned int h); virtual ~Display(); virtual void Initialise() = 0; @@ -57,8 +55,6 @@ class Display unsigned int GetWidth(); unsigned int GetHeight(); - pov_base::GammaCurvePtr GetGamma(); - virtual void DrawPixel(unsigned int x, unsigned int y, const RGBA8& colour) = 0; virtual void DrawRectangleFrame(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, const RGBA8& colour); @@ -72,8 +68,6 @@ class Display unsigned int width; /// display height unsigned int height; - /// display gamma correction factor - pov_base::GammaCurvePtr gamma; /// not available Display(); diff --git a/source/frontend/imagemessagehandler.cpp b/source/frontend/imagemessagehandler.cpp index 8af713907..084601d86 100644 --- a/source/frontend/imagemessagehandler.cpp +++ b/source/frontend/imagemessagehandler.cpp @@ -36,9 +36,13 @@ // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config) #include "frontend/imagemessagehandler.h" +// POV-Ray header files (base module) +#include "base/image/colourspace.h" +#include "base/image/dither.h" #include "base/image/encoding.h" #include "base/image/image.h" +// POV-Ray header files (frontend module) #include "frontend/display.h" #include "frontend/renderfrontend.h" @@ -96,10 +100,6 @@ void ImageMessageHandler::DrawPixelSet(const SceneData& sd, const ViewData& vd, if((pixelpositions.size() / 2) != (pixelcolors.size() / 5)) throw POV_EXCEPTION(kInvalidDataSizeErr, "Number of pixel colors and pixel positions does not match!"); - GammaCurvePtr gamma; - if (vd.display != nullptr) - gamma = vd.display->GetGamma(); - for(int i = 0, ii = 0; (i < pixelcolors.size()) && (ii < pixelpositions.size()); i += 5, ii += 2) { RGBTColour col(pixelcolors[i], pixelcolors[i + 1], pixelcolors[i + 2], pixelcolors[i + 4]); // NB pixelcolors[i + 3] is an unused channel @@ -114,12 +114,21 @@ void ImageMessageHandler::DrawPixelSet(const SceneData& sd, const ViewData& vd, // TODO ALPHA - display may profit from receiving the data in its original, premultiplied form // Premultiplied alpha was good for the math, but the display expects non-premultiplied alpha, so fix this if possible. AlphaUnPremultiply(gcol); - } - rgba.red = IntEncode(gamma, gcol.red(), 255, dither); - rgba.green = IntEncode(gamma, gcol.green(), 255, dither); - rgba.blue = IntEncode(gamma, gcol.blue(), 255, dither); - rgba.alpha = IntEncode( gcol.alpha(), 255, dither); + if (vd.greyscaleDisplay) + { + rgba.red = IntEncode(vd.displayGamma, gcol.Greyscale(), 255, dither); + rgba.green = rgba.red; + rgba.blue = rgba.red; + } + else + { + rgba.red = IntEncode(vd.displayGamma, gcol.red(), 255, dither); + rgba.green = IntEncode(vd.displayGamma, gcol.green(), 255, dither); + rgba.blue = IntEncode(vd.displayGamma, gcol.blue(), 255, dither); + } + rgba.alpha = IntEncode(gcol.alpha(), 255, dither); + } if(psize == 1) { @@ -168,11 +177,6 @@ void ImageMessageHandler::DrawPixelBlockSet(const SceneData& sd, const ViewData& cols.reserve(rect.GetArea()); rgbas.reserve(rect.GetArea()); - GammaCurvePtr gamma; - - if (vd.display != nullptr) - gamma = vd.display->GetGamma(); - for(i = 0; i < rect.GetArea() * 5; i += 5) { RGBTColour col(pixelvector[i], pixelvector[i + 1], pixelvector[i + 2], pixelvector[i + 4]); // NB pixelvector[i + 3] is an unused channel @@ -187,15 +191,24 @@ void ImageMessageHandler::DrawPixelBlockSet(const SceneData& sd, const ViewData& // TODO ALPHA - display may profit from receiving the data in its original, premultiplied form // Premultiplied alpha was good for the math, but the display expects non-premultiplied alpha, so fix this if possible. AlphaUnPremultiply(gcol); - } - rgba.red = IntEncode(gamma, gcol.red(), 255, dither); - rgba.green = IntEncode(gamma, gcol.green(), 255, dither); - rgba.blue = IntEncode(gamma, gcol.blue(), 255, dither); - rgba.alpha = IntEncode( gcol.alpha(), 255, dither); + if (vd.greyscaleDisplay) + { + rgba.red = IntEncode(vd.displayGamma, gcol.Greyscale(), 255, dither); + rgba.green = rgba.red; + rgba.blue = rgba.red; + } + else + { + rgba.red = IntEncode(vd.displayGamma, gcol.red(), 255, dither); + rgba.green = IntEncode(vd.displayGamma, gcol.green(), 255, dither); + rgba.blue = IntEncode(vd.displayGamma, gcol.blue(), 255, dither); + } + rgba.alpha = IntEncode(gcol.alpha(), 255, dither); + rgbas.push_back(rgba); + } cols.push_back(col); - rgbas.push_back(rgba); } if (vd.display != nullptr) diff --git a/source/frontend/imageprocessing.cpp b/source/frontend/imageprocessing.cpp index c5236f718..cc5007105 100644 --- a/source/frontend/imageprocessing.cpp +++ b/source/frontend/imageprocessing.cpp @@ -36,10 +36,14 @@ // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config) #include "frontend/imageprocessing.h" -#include +// Standard C++ header files +#include +// POV-Ray header files (base module) +#include "base/image/dither.h" #include "base/image/image.h" +// POV-Ray header files (POVMS module) #include "povms/povmsid.h" // this must be the last file included @@ -104,7 +108,7 @@ UCS2String ImageProcessing::WriteImage(POVMS_Object& ropts, POVMSInt frame, int Image::ImageFileType imagetype = Image::SYS; unsigned int filetype = POV_File_Image_System; - wopts.bitsPerChannel = clip(ropts.TryGetInt(kPOVAttrib_BitsPerColor, 8), 5, 16); + wopts.bitsPerChannel = clip(ropts.TryGetInt(kPOVAttrib_BitsPerColor, 8), 1, 16); wopts.alphaMode = (ropts.TryGetBool(kPOVAttrib_OutputAlpha, false) ? Image::kAlphaMode_Default : Image::kAlphaMode_None ); wopts.compression = (ropts.Exist(kPOVAttrib_Compression) ? clip(ropts.GetInt(kPOVAttrib_Compression), 0, 255) : -1); wopts.grayscale = ropts.TryGetBool(kPOVAttrib_GrayscaleOutput, false); @@ -173,9 +177,9 @@ UCS2String ImageProcessing::WriteImage(POVMS_Object& ropts, POVMSInt frame, int wopts.workingGamma = GetGammaCurve(gammaType, gamma); bool dither = ropts.TryGetBool(kPOVAttrib_Dither, false); - DitherMethodId ditherMethod = kPOVList_DitherMethod_None; + DitherMethodId ditherMethod = DitherMethodId::kNone; if (dither) - ditherMethod = (DitherMethodId)ropts.TryGetInt(kPOVAttrib_DitherMethod, kPOVList_DitherMethod_FloydSteinberg); + ditherMethod = ropts.TryGetEnum(kPOVAttrib_DitherMethod, DitherMethodId::kBlueNoise); wopts.ditherStrategy = GetDitherStrategy(ditherMethod, image->GetWidth()); // in theory this should always return a filename since the frontend code @@ -184,7 +188,7 @@ UCS2String ImageProcessing::WriteImage(POVMS_Object& ropts, POVMSInt frame, int if(filename.empty() == true) filename = GetOutputFilename(ropts, frame, digits); - boost::scoped_ptr imagefile(NewOStream(filename.c_str(), filetype, false)); // TODO - check file permissions somehow without macro [ttrf] + std::unique_ptr imagefile(NewOStream(filename.c_str(), filetype, false)); // TODO - check file permissions somehow without macro [ttrf] if (imagefile == nullptr) throw POV_EXCEPTION_CODE(kCannotOpenFileErr); diff --git a/source/frontend/processrenderoptions.cpp b/source/frontend/processrenderoptions.cpp index 0db38b434..162d58734 100644 --- a/source/frontend/processrenderoptions.cpp +++ b/source/frontend/processrenderoptions.cpp @@ -43,6 +43,7 @@ #include "base/fileutil.h" #include "base/platformbase.h" #include "base/image/colourspace.h" +#include "base/image/dither.h" #include "base/image/encoding.h" // POV-Ray header files (POVMS module) @@ -346,7 +347,6 @@ struct ProcessOptions::Cmd_Parser_Table RenderOptions_Cmd_Table[] = { nullptr } }; -// TODO FIXME - The following are hacks of some sort, no idea what they are good for. They certainly use wrong types and probably contain other mistakes [trf] extern struct ProcessRenderOptions::Parameter_Code_Table DitherMethodTable[]; ProcessRenderOptions::ProcessRenderOptions() : ProcessOptions(RenderOptions_INI_Table, RenderOptions_Cmd_Table) @@ -577,25 +577,22 @@ int ProcessRenderOptions::ReadSpecialSwitchHandler(Cmd_Parser_Table *option, cha err = POVMSUtil_SetInt(obj, option->key, intval); file_type = *param++; } - if ((err == kNoErr) && (*param > ' ')) + if ((err == kNoErr) && (tolower(*param) == 'g')) { - if (tolower(*param) == 'g') + if(!has16BitGrayscale) { - if(!has16BitGrayscale) - { - ParseError("Grayscale not currently supported with output file format '%c'.", file_type); - err = kParamErr; - } - else - { - if ((err = POVMSUtil_SetBool(obj, kPOVAttrib_GrayscaleOutput, true)) == kNoErr && *++param > ' ') - { - ParseError("Unexpected '%s' following grayscale flag in +F%c option.", param, file_type); - err = kParamErr; - } - } + ParseError("Grayscale not currently supported with output file format '%c'.", file_type); + err = kParamErr; } - else if (isdigit(*param) != 0) + else + { + err = POVMSUtil_SetBool(obj, kPOVAttrib_GrayscaleOutput, true); + ++param; + } + } + if ((err == kNoErr) && (*param > ' ')) + { + if (isdigit(*param) != 0) { if (sscanf(param, "%d%n", &intval, &intval2) == 1) { @@ -1076,7 +1073,7 @@ struct ProcessRenderOptions::Output_FileType_Table FileTypeTable[] = #endif // POV_SYS_IMAGE_TYPE // [1] Alpha support for BMP uses an unofficial extension to the BMP file format, which is not recognized by - // most image pocessing software. + // most image processing software. // [2] While OpenEXR does support greyscale output at >8 bits, the variants currently supported by POV-Ray // use 16-bit floating-point values with 10 bit mantissa, which might be insufficient for various purposes @@ -1091,12 +1088,12 @@ struct ProcessRenderOptions::Parameter_Code_Table GammaTypeTable[] = { // code, internalId, - { "BT709", kPOVList_GammaType_BT709 }, - { "BT2020", kPOVList_GammaType_BT2020 }, - { "SRGB", kPOVList_GammaType_SRGB }, + { "BT709", kPOVList_GammaType_BT709, "ITU-R BT.709 transfer function" }, + { "BT2020", kPOVList_GammaType_BT2020, "ITU-R BT.2020 transfer function" }, + { "SRGB", kPOVList_GammaType_SRGB, "sRGB transfer function" }, // end-of-list marker - { nullptr, 0 } + { nullptr, 0, "(unknown)" } }; /* Supported dither types */ @@ -1104,15 +1101,23 @@ struct ProcessRenderOptions::Parameter_Code_Table DitherMethodTable[] = { // code, internalId, - { "B2", kPOVList_DitherMethod_Bayer2x2 }, - { "B3", kPOVList_DitherMethod_Bayer3x3 }, - { "B4", kPOVList_DitherMethod_Bayer4x4 }, - { "D1", kPOVList_DitherMethod_Diffusion1D }, - { "D2", kPOVList_DitherMethod_Diffusion2D }, - { "FS", kPOVList_DitherMethod_FloydSteinberg }, + { "AT", int(DitherMethodId::kAtkinson), "Atkinson error diffusion" }, + { "B2", int(DitherMethodId::kBayer2x2), "2x2 Bayer pattern" }, + { "B3", int(DitherMethodId::kBayer3x3), "3x3 Bayer pattern" }, + { "B4", int(DitherMethodId::kBayer4x4), "4x4 Bayer pattern" }, + { "BK", int(DitherMethodId::kBurkes), "Burkes error diffusion" }, + { "BNX", int(DitherMethodId::kBlueNoiseX), "Blue noise pattern (inverted for Red/Blue)" }, + { "BN", int(DitherMethodId::kBlueNoise), "Blue noise pattern" }, + { "D1", int(DitherMethodId::kDiffusion1D), "Simple 1-D error diffusion" }, + { "D2", int(DitherMethodId::kSierraLite), "Simple 2-D error diffusion (Sierra Lite)" }, + { "FS", int(DitherMethodId::kFloydSteinberg), "Floyd-Steinberg error diffusion" }, + { "JN", int(DitherMethodId::kJarvisJudiceNinke),"Jarvis-Judice-Ninke error diffusion" }, + { "S2", int(DitherMethodId::kSierra2), "Two-row Sierra error diffusion" }, + { "S3", int(DitherMethodId::kSierra3), "Sierra error diffusion" }, + { "ST", int(DitherMethodId::kStucki), "Stucki error diffusion" }, // end-of-list marker - { nullptr, 0 } + { nullptr, 0, "(unknown)" } }; int ProcessRenderOptions::ParseFileType(char code, POVMSType attribute, int* pInternalId, bool* pHas16BitGreyscale) @@ -1173,6 +1178,16 @@ const char* ProcessRenderOptions::UnparseGammaType(int gammaType) return UnparseParameterCode(GammaTypeTable, gammaType); } +const char* ProcessRenderOptions::GetGammaTypeText(int gammaType) +{ + return GetParameterCodeText(GammaTypeTable, gammaType); +} + +const char* ProcessRenderOptions::GetDitherMethodText(int ditherMethod) +{ + return GetParameterCodeText(DitherMethodTable, ditherMethod); +} + int ProcessRenderOptions::ParseParameterCode(const ProcessRenderOptions::Parameter_Code_Table* codeTable, char* code, int* pInternalId) { for (int i = 0; code[i] != '\0'; i ++) @@ -1196,4 +1211,13 @@ const char* ProcessRenderOptions::UnparseParameterCode(const ProcessRenderOption return nullptr; } +const char* ProcessRenderOptions::GetParameterCodeText(const ProcessRenderOptions::Parameter_Code_Table* codeTable, int internalId) +{ + int i; + for (i = 0; codeTable[i].code != nullptr; i++) + if (internalId == codeTable[i].internalId) + break; + return codeTable[i].text; +} + } diff --git a/source/frontend/processrenderoptions.h b/source/frontend/processrenderoptions.h index 4e4b80f09..4c2d7995b 100644 --- a/source/frontend/processrenderoptions.h +++ b/source/frontend/processrenderoptions.h @@ -79,14 +79,18 @@ class ProcessRenderOptions : public ProcessOptions { const char* code; // code used in INI and command line options int internalId; // e.g. kPOVList_GammaType_* + const char* text; // human-readable text }; int ParseFileType(char, POVMSType, int*, bool* pHas16BitGreyscale = nullptr); - char UnparseFileType(int); + static char UnparseFileType(int); int ParseGammaType(char*, int*); - const char* UnparseGammaType(int); - int ParseParameterCode(const ProcessRenderOptions::Parameter_Code_Table* codeTable, char* code, int* pInternalId); - const char* UnparseParameterCode(const ProcessRenderOptions::Parameter_Code_Table* codeTable, int internalId); + static const char* UnparseGammaType(int); + static const char* GetGammaTypeText(int); + static const char* GetDitherMethodText(int); + static int ParseParameterCode(const ProcessRenderOptions::Parameter_Code_Table* codeTable, char* code, int* pInternalId); + static const char* UnparseParameterCode(const ProcessRenderOptions::Parameter_Code_Table* codeTable, int internalId); + static const char* GetParameterCodeText(const ProcessRenderOptions::Parameter_Code_Table* codeTable, int internalId); }; } diff --git a/source/frontend/renderfrontend.cpp b/source/frontend/renderfrontend.cpp index bc6c6e388..4c9aa1adb 100644 --- a/source/frontend/renderfrontend.cpp +++ b/source/frontend/renderfrontend.cpp @@ -36,17 +36,23 @@ // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config) #include "frontend/renderfrontend.h" -#include +// Standard C++ header files +#include +// POV-Ray header files (base module) #include "base/platformbase.h" #include "base/textstream.h" #include "base/textstreambuffer.h" +#include "base/image/dither.h" #include "base/image/encoding.h" +// POV-Ray header files (POVMS module) #include "povms/povmsid.h" +// POV-Ray header files (frontend module) #include "frontend/console.h" #include "frontend/processoptions.h" +#include "frontend/processrenderoptions.h" // this must be the last file included #include "base/povdebug.h" @@ -644,7 +650,7 @@ void RenderFrontendBase::ContinueBackup(POVMS_Object& ropts, ViewData& vd, ViewI vd.imageBackup.reset(); MakeBackupPath(ropts, vd, outputpath); - boost::scoped_ptr inbuffer(new IFileStream(vd.imageBackupFile().c_str())); + std::unique_ptr inbuffer(new IFileStream(vd.imageBackupFile().c_str())); size_t pos = sizeof(Backup_File_Header); @@ -1158,19 +1164,9 @@ void OutputOptions(POVMS_Object& cppmsg, TextStreamBuffer *tsb) (void)POVMSUtil_GetBool(msg, kPOVAttrib_Dither, &b); if (b) { - i = kPOVList_DitherMethod_FloydSteinberg; + i = int(DitherMethodId::kBlueNoise); (void)POVMSUtil_GetInt(msg, kPOVAttrib_DitherMethod, &i); - switch(i) - { - // TODO FIXME - for easier maintenance, this should probably be part of the DitherMethodTable. - case kPOVList_DitherMethod_Bayer2x2: t = "2x2 Bayer pattern"; break; - case kPOVList_DitherMethod_Bayer3x3: t = "3x3 Bayer pattern"; break; - case kPOVList_DitherMethod_Bayer4x4: t = "4x4 Bayer pattern"; break; - case kPOVList_DitherMethod_Diffusion1D: t = "simple 1-D error diffusion"; break; - case kPOVList_DitherMethod_Diffusion2D: t = "simple 2-D error diffusion"; break; - case kPOVList_DitherMethod_FloydSteinberg: t = "Floyd-Steinberg error diffusion"; break; - default: t = "(unknown)"; break; - } + t = ProcessRenderOptions::GetDitherMethodText(i); tsb->printf(" Dithering............%s\n", t); } else @@ -1196,17 +1192,10 @@ void OutputOptions(POVMS_Object& cppmsg, TextStreamBuffer *tsb) case kPOVList_GammaType_PowerLaw: tsb->printf(" Graphic display......On (gamma: %g)\n", (float)f); break; - case kPOVList_GammaType_SRGB: - tsb->printf(" Graphic display......On (gamma: sRGB)\n"); - break; - case kPOVList_GammaType_BT709: - tsb->printf(" Graphic display......On (gamma: ITU-R BT.709)\n"); - break; - case kPOVList_GammaType_BT2020: - tsb->printf(" Graphic display......On (gamma: ITU-R BT.2020)\n"); - break; default: - throw POV_EXCEPTION_STRING("Unknown gamma mode in OutputOptions()"); + t = ProcessRenderOptions::GetGammaTypeText(i); + tsb->printf(" Graphic display......On (gamma: %s)\n", t); + break; } } else diff --git a/source/frontend/renderfrontend.h b/source/frontend/renderfrontend.h index 30074d901..92ff2db22 100644 --- a/source/frontend/renderfrontend.h +++ b/source/frontend/renderfrontend.h @@ -46,7 +46,6 @@ #include "base/path.h" #include "base/platformbase.h" -#include "base/image/colourspace.h" #include "base/image/image.h" #include "frontend/console.h" @@ -143,6 +142,8 @@ struct ViewData mutable shared_ptr image; mutable shared_ptr display; mutable shared_ptr imageBackup; + GammaCurvePtr displayGamma; + bool greyscaleDisplay; Path imageBackupFile; }; @@ -286,7 +287,7 @@ class RenderFrontend : public RenderFrontendBase void ResumeParser(SceneId sid); void StopParser(SceneId sid); - ViewId CreateView(SceneId sid, POVMS_Object& obj, shared_ptr& imageProcessing, boost::function fn); + ViewId CreateView(SceneId sid, POVMS_Object& obj, shared_ptr& imageProcessing, boost::function fn); void CloseView(ViewId vid); ViewData::ViewState GetViewState(ViewId vid); @@ -435,7 +436,7 @@ void RenderFrontend::StopParser(SceneId } template -RenderFrontendBase::ViewId RenderFrontend::CreateView(SceneId sid, POVMS_Object& obj, shared_ptr& imageProcessing, boost::function fn) +RenderFrontendBase::ViewId RenderFrontend::CreateView(SceneId sid, POVMS_Object& obj, shared_ptr& imageProcessing, boost::function fn) { typename SceneHandlerMap::iterator shi(scenehandler.find(sid)); @@ -522,6 +523,9 @@ RenderFrontendBase::ViewId RenderFrontend(fn(width, height, gamma)); + vh.data.display = shared_ptr(fn(width, height)); viewhandler[vid] = vh; view2scene[vid] = sid; diff --git a/source/frontend/simplefrontend.h b/source/frontend/simplefrontend.h index 026d81298..6e39fcceb 100644 --- a/source/frontend/simplefrontend.h +++ b/source/frontend/simplefrontend.h @@ -85,7 +85,7 @@ class SimpleFrontend public: SimpleFrontend(POVMSContext ctx, POVMSAddress addr, POVMS_Object& msg, boost::function cfn, - boost::function dfn, + boost::function dfn, POVMS_Object *result = nullptr, shared_ptr console = shared_ptr()); ~SimpleFrontend(); @@ -112,13 +112,13 @@ class SimpleFrontend shared_ptr animationProcessing; shared_ptr shelloutProcessing; boost::function createConsole; - boost::function createDisplay; + boost::function createDisplay; }; template SimpleFrontend::SimpleFrontend(POVMSContext ctx, POVMSAddress addr, POVMS_Object& msg, boost::function cfn, - boost::function dfn, + boost::function dfn, POVMS_Object *result, shared_ptr console) : renderFrontend(ctx), backendAddress(addr), diff --git a/source/parser/parser.cpp b/source/parser/parser.cpp index a5b878ffa..fd08ba2cd 100644 --- a/source/parser/parser.cpp +++ b/source/parser/parser.cpp @@ -11220,13 +11220,13 @@ bool Parser::POV_ARRAY::HasElement(size_t i) const const TokenId& Parser::POV_ARRAY::ElementType(size_t i) const { - POV_PARSER_ASSERT(i < DataPtrs.size()); + POV_PARSER_ASSERT(resizable || (i < DataPtrs.size())); return (mixedType ? Types[i] : Type_); } TokenId& Parser::POV_ARRAY::ElementType(size_t i) { - POV_PARSER_ASSERT(i < DataPtrs.size()); + POV_PARSER_ASSERT(resizable || (i < DataPtrs.size())); return (mixedType ? Types[i] : Type_); } diff --git a/source/parser/parser_tokenizer.cpp b/source/parser/parser_tokenizer.cpp index eb00c53cd..3d45f3d78 100644 --- a/source/parser/parser_tokenizer.cpp +++ b/source/parser/parser_tokenizer.cpp @@ -627,6 +627,7 @@ void Parser::Read_Symbol(const RawToken& rawToken) haveNextRawToken = PeekRawToken(nextRawToken); + SYM_TABLE* parentTable = table; if (pseudoDictionary >= 0) { table = Tables [pseudoDictionary]; @@ -686,6 +687,7 @@ void Parser::Read_Symbol(const RawToken& rawToken) else { breakLoop = true; + table = parentTable; break; } @@ -2870,8 +2872,11 @@ void Parser::Parse_Initalizer (int Sub, size_t Base, POV_ARRAY *a) CASE (RIGHT_CURLY_TOKEN) if (a->resizable) + { + finalParameter = true; // We reserved one element too many. a->Shrink(); + } else { if (!(finalParameter && properlyDelimited)) diff --git a/source/povmain.cpp b/source/povmain.cpp index eb0e0bd85..6e0eb3a0c 100644 --- a/source/povmain.cpp +++ b/source/povmain.cpp @@ -42,7 +42,6 @@ #include "frontend/configfrontend.h" #include "base/timer.h" -#include "base/image/colourspace.h" #include "backend/povray.h" @@ -72,23 +71,23 @@ class DefaultConsole : public pov_frontend::Console class DefaultDisplay : public pov_frontend::Display { public: - DefaultDisplay(unsigned int w, unsigned int h, pov_base::GammaCurvePtr g) : Display(w, h, g) { } + DefaultDisplay(unsigned int w, unsigned int h) : Display(w, h) { } ~DefaultDisplay() { } void Initialise() { } void DrawPixel(unsigned int, unsigned int, const RGBA8&) { } }; pov_frontend::Console *CreateDefaultConsole(); -pov_frontend::Display *CreateDefaultDisplay(unsigned int w, unsigned int h, pov_base::GammaCurvePtr gf); +pov_frontend::Display *CreateDefaultDisplay(unsigned int w, unsigned int h); pov_frontend::Console *CreateDefaultConsole() { return new DefaultConsole(); } -pov_frontend::Display *CreateDefaultDisplay(unsigned int w, unsigned int h, pov_base::GammaCurvePtr gf) +pov_frontend::Display *CreateDefaultDisplay(unsigned int w, unsigned int h) { - return new DefaultDisplay(w, h, gf); + return new DefaultDisplay(w, h); } void BackendExitCallback() @@ -125,7 +124,7 @@ int main(int argc, char **argv) POVMS_Object backendMessage; SimpleFrontend frontend(frontendContext, backendAddress, backendMessage, - boost::bind(CreateDefaultConsole), boost::bind(CreateDefaultDisplay, _1, _2, _3)); + boost::bind(CreateDefaultConsole), boost::bind(CreateDefaultDisplay, _1, _2)); // Print help screens if(argc == 1) diff --git a/source/povms/povmscpp.h b/source/povms/povmscpp.h index e04226006..f0e7c44f4 100644 --- a/source/povms/povmscpp.h +++ b/source/povms/povmscpp.h @@ -252,6 +252,8 @@ class POVMS_Object : public POVMS_Container POVMSUCS2String TryGetUCS2String(POVMSType key, const char *alt); POVMSUCS2String TryGetUCS2String(POVMSType key, const POVMSUCS2String& alt); POVMSInt TryGetInt(POVMSType key, POVMSInt alt); + template T TryGetEnum(POVMSType key, T alt) + { return static_cast(TryGetInt(key, static_cast(alt))); } POVMSLong TryGetLong(POVMSType key, POVMSLong alt); POVMSFloat TryGetFloat(POVMSType key, POVMSFloat alt); POVMSBool TryGetBool(POVMSType key, POVMSBool alt); diff --git a/tools/meta-make/Makefile b/tools/meta-make/Makefile new file mode 100644 index 000000000..0aeafb9aa --- /dev/null +++ b/tools/meta-make/Makefile @@ -0,0 +1,95 @@ +#************************************************************************************* +# Location of Stuff + +# Location of everything +rootdir = ../.. + +# Location of generated source files +fontsrc = $(rootdir)/source/base/font +scenesrc = $(rootdir)/source/backend/control +bluenoisesrc = $(rootdir)/source/base/data + +# Location of input files +include = $(rootdir)/distribution/include +scenes = $(rootdir)/distribution/scenes + +# Location of tools +metamake = $(rootdir)/tools/meta-make +reswrap_header = $(metamake)/reswrap-header.cpp +reswrap_sh = $(metamake)/reswrap.sh +metagen_header = $(metamake)/metagen-header.cpp +metagen_sh = $(metamake)/metagen.sh + +#************************************************************************************* +# What to Generate + +FONTS = crystal cyrvetic povlogo timrom +BENCHMARK = benchmark_pov benchmark_ini +BLUENOISE = bluenoise64a + +#------------------------------------------------------------------------------------- +# Generation Parameters + +# File Identifier Seed Size [Slices] +bluenoise64a_opts = kBlueNoise64a 4711 64 + +#------------------------------------------------------------------------------------- +# Files to Generate + +FONTFILES = $(foreach font,$(FONTS),$(addprefix $(fontsrc)/$(font),.cpp .h)) +BENCHMARKFILES = $(foreach scene,$(BENCHMARK),$(addprefix $(scenesrc)/$(scene),.cpp .h)) +BLUENOISEFILES = $(foreach noise,$(BLUENOISE),$(addprefix $(bluenoisesrc)/$(noise),.cpp .h)) + +ALLFILES = $(FONTFILES) $(BENCHMARKFILES) $(BLUENOISEFILES) + +#************************************************************************************* +# Rules + +.PHONY: all +all: $(ALLFILES) + +.PHONY: clean +clean: + -rm $(ALLFILES) + +#------------------------------------------------------------------------------------- +# Fonts + +vpath %.ttf $(include) + +$(fontsrc)/%.cpp: %.ttf $(reswrap_header) + $(reswrap_sh) "$@" "$<" "pov_base" "font_$(*F)" "-z" + +$(fontsrc)/%.h: %.ttf $(reswrap_header) + $(reswrap_sh) "$@" "$<" "pov_base" "font_$(*F)" "-z" + +#------------------------------------------------------------------------------------- +# Scenes + +vpath %.ini $(scenes) +vpath %.pov $(scenes) + +$(scenesrc)/benchmark_ini.%: advanced/benchmark/benchmark.ini $(reswrap_header) + $(reswrap_sh) "$@" "$<" "pov" "Benchmark_Options" "-m -ta -c 120" + +$(scenesrc)/benchmark_pov.%: advanced/benchmark/benchmark.pov $(reswrap_header) + $(reswrap_sh) "$@" "$<" "pov" "Benchmark_File" "-m -ta -c 120" + +#------------------------------------------------------------------------------------- +# Blue Noise Patterns + +$(BLUENOISEFILES): GENOPTS = $($(basename $(@F))_opts) +$(BLUENOISEFILES): NAME = $(word 1, $(GENOPTS)) +$(BLUENOISEFILES): SEED = $(word 2, $(GENOPTS)) +$(BLUENOISEFILES): SIZE = $(word 3, $(GENOPTS)) +$(BLUENOISEFILES): SLICES = $(word 4, $(GENOPTS)) + +define metagen_bluenoise = +$(metagen_sh) "$@" "Blue noise pattern data" "python $(metamake)/bluenoise/metagen-bluenoise.py" +endef + +$(BLUENOISEFILES): %: $(metagen_header) + $(metagen_bluenoise) "-l -npov_base -r$(SEED) $(NAME) $(SIZE) $(SIZE) $(SLICES)" "-h" + +#************************************************************************************* +# End of File diff --git a/tools/meta-make/bluenoise/BlueNoise.py b/tools/meta-make/bluenoise/BlueNoise.py new file mode 100644 index 000000000..03bdf27bc --- /dev/null +++ b/tools/meta-make/bluenoise/BlueNoise.py @@ -0,0 +1,418 @@ +# BlueNoise.py - An implementation of the void and cluster method for generation of +# blue noise dither arrays and related utilities. +# +# Written in 2016 by Christoph Peters, Christoph(at)MomentsInGraphics.de +# +# To the extent possible under law, the author(s) have dedicated all copyright and +# related and neighboring rights to this software to the public domain worldwide. +# This software is distributed without any warranty. +# +# You should have received a copy of the CC0 Public Domain Dedication along with +# this software. If not, see . + +from os import path,makedirs +import numpy as np +from scipy import ndimage +from matplotlib import pyplot +import png +import threading +import struct + +def GetBayerPattern(Log2Width): + """Creates a two-dimensional Bayer pattern with a width and height of + 2**Log2Width.""" + X,Y=np.meshgrid(range(2**Log2Width),range(2**Log2Width)); + Result=np.zeros_like(X); + for i in range(Log2Width): + StripesY=np.where(np.bitwise_and(Y,2**(Log2Width-1-i))!=0,1,0); + StripesX=np.where(np.bitwise_and(X,2**(Log2Width-1-i))!=0,1,0); + Checker=np.bitwise_xor(StripesX,StripesY); + Result+=np.bitwise_or(StripesY*2**(2*i),Checker*2**(2*i+1)); + return Result; + + +def FindLargestVoid(BinaryPattern,StandardDeviation): + """This function returns the indices of the largest void in the given binary + pattern as defined by Ulichney. + \param BinaryPattern A boolean array (should be two-dimensional although the + implementation works in arbitrary dimensions). + \param StandardDeviation The standard deviation used for the Gaussian filter + in pixels. This can be a single float for an isotropic Gaussian or a + tuple with one float per dimension for an anisotropic Gaussian. + \return A flat index i such that BinaryPattern.flat[i] corresponds to the + largest void. By definition this is a majority pixel. + \sa GetVoidAndClusterBlueNoise""" + # The minority value is always True for convenience + if(np.count_nonzero(BinaryPattern)*2>=np.size(BinaryPattern)): + BinaryPattern=np.logical_not(BinaryPattern); + # Apply the Gaussian. We do not want to cut off the Gaussian at all because even + # the tiniest difference can change the ranking. Therefore we apply the Gaussian + # through a fast Fourier transform by means of the convolution theorem. + FilteredArray=np.fft.ifftn(ndimage.fourier.fourier_gaussian(np.fft.fftn(np.where(BinaryPattern,1.0,0.0)),StandardDeviation)).real; + # Find the largest void + return np.argmin(np.where(BinaryPattern,2.0,FilteredArray)); + + +def FindTightestCluster(BinaryPattern,StandardDeviation): + """Like FindLargestVoid() but finds the tightest cluster which is a minority + pixel by definition. + \sa GetVoidAndClusterBlueNoise""" + if(np.count_nonzero(BinaryPattern)*2>=np.size(BinaryPattern)): + BinaryPattern=np.logical_not(BinaryPattern); + FilteredArray=np.fft.ifftn(ndimage.fourier.fourier_gaussian(np.fft.fftn(np.where(BinaryPattern,1.0,0.0)),StandardDeviation)).real; + return np.argmax(np.where(BinaryPattern,FilteredArray,-1.0)); + + +def GetVoidAndClusterBlueNoise(OutputShape,StandardDeviation=1.5,InitialSeedFraction=0.1): + """Generates a blue noise dither array of the given shape using the method + proposed by Ulichney [1993] in "The void-and-cluster method for dither array + generation" published in Proc. SPIE 1913. + \param OutputShape The shape of the output array. This function works in + arbitrary dimension, i.e. OutputShape can have arbitrary length. Though + it is only tested for the 2D case where you should pass a tuple + (Height,Width). + \param StandardDeviation The standard deviation in pixels used for the + Gaussian filter defining largest voids and tightest clusters. Larger + values lead to more low-frequency content but better isotropy. Small + values lead to more ordered patterns with less low-frequency content. + Ulichney proposes to use a value of 1.5. If you want an anisotropic + Gaussian, you can pass a tuple of length len(OutputShape) with one + standard deviation per dimension. + \param InitialSeedFraction The only non-deterministic step in the algorithm + marks a small number of pixels in the grid randomly. This parameter + defines the fraction of such points. It has to be positive but less + than 0.5. Very small values lead to ordered patterns, beyond that there + is little change. + \return An integer array of shape OutputShape containing each integer from 0 + to np.prod(OutputShape)-1 exactly once.""" + nRank=np.prod(OutputShape); + # Generate the initial binary pattern with a prescribed number of ones + nInitialOne=max(1,min(int((nRank-1)/2),int(nRank*InitialSeedFraction))); + # Start from white noise (this is the only randomized step) + InitialBinaryPattern=np.zeros(OutputShape,dtype=np.bool); + InitialBinaryPattern.flat=np.random.permutation(np.arange(nRank))=np.cos(np.pi/32.0)); + AngularPower[i]=np.sum(np.where(FullMask,np.abs(DFT),0.0))/np.count_nonzero(FullMask); + MeanAngularPower=np.mean(AngularPower[1:]); + DenseAngle=np.linspace(0.0,2.0*np.pi,256); + pyplot.plot(np.cos(DenseAngle)*MeanAngularPower,np.sin(DenseAngle)*MeanAngularPower,color=(0.7,0.7,0.7)); + pyplot.plot(np.cos(BinningAngle)*AngularPower,np.sin(BinningAngle)*AngularPower); + return FigureList; + + +def PlotBinaryPatterns(Texture,nPatternRow,nPatternColumn): + """This function creates a figure with a grid of thresholded versions of the + given 2D noise texture. It assumes that each value from 0 to + np.size(Texture)-1 is contained exactly once. + \return The created figure. + \note For the plots to show you have to invoke pyplot.show().""" + Figure=pyplot.figure(); + nPattern=nPatternRow*nPatternColumn+1; + for i in range(1,nPattern): + Figure.add_subplot(nPatternRow,nPatternColumn,i,xticks=[],yticks=[]); + pyplot.imshow(np.where(Texture*nPattern4 the + superfluous channels are ignored. If nChannel<4 the data is expanded. + The alpha channel is set to 255, green and blue are filled with black + or with duplicates of red if nChannel==1. It is assumed that each + channel contains every integer value from 0 to nRank-1 exactly once. + The range of values is remapped linearly to span the range from 0 to + 255. + \param OutputPNGFilePath The path to the output png file including the file + format extension. + \param nRank Defaults to Width*Height if you pass a non-positive value.""" + # Scale the array to an LDR version + if(nRank<=0): + nRank=Texture.shape[0]*Texture.shape[1]; + Texture=np.asarray((Texture*256)//nRank,dtype=np.uint8); + # Get a three-dimensional array + if(len(Texture.shape)<3): + Texture=Texture[:,:,np.newaxis]; + # Generate channels as needed + if(Texture.shape[2]==1): + Texture=np.dstack([Texture]*3+[255*np.ones_like(Texture[:,:,0])]); + elif(Texture.shape[2]==2): + Texture=np.dstack([Texture[:,:,0],Texture[:,:,1]]+[np.zeros_like(Texture[:,:,0])]+[255*np.ones_like(Texture[:,:,0])]); + elif(Texture.shape[2]==3): + Texture=np.dstack([Texture[:,:,0],Texture[:,:,1],Texture[:,:,2]]+[255*np.ones_like(Texture[:,:,0])]); + elif(Texture.shape[2]>4): + Texture=Texture[:,:,:4]; + # Save the image + png.from_array(Texture,"RGBA;8").save(OutputPNGFilePath); + + +def StoreNoiseTextureHDR(Texture,OutputPNGFilePath,nRank=-1): + """This function stores the given texture to an HDR png file with 16 bits per + channel and the specified number of channels. + \param Texture An array of shape (Height,Width) or (Height,Width,nChannel). + The former is handled like (Height,Width,1). It is assumed that each + channel contains each integer value from 0 to nRank-1 exactly once. The + range of values is remapped linearly to span the range from 0 to + 2**16-1 supported by the output format. nChannel can be 1, 2, 3 or 4. + \param OutputPNGFilePath The path to the output *.png file including the file + format extension. + \param nRank Defaults to Width*Height if you pass a non-positive value.""" + # Scale the array to an HDR version + if(nRank<=0): + nRank=Texture.shape[0]*Texture.shape[1]; + Texture=np.asarray((np.asarray(Texture,dtype=np.uint64)*(2**16))//nRank,dtype=np.uint16); + # Get a three-dimensional array + if(len(Texture.shape)<3): + Texture=Texture[:,:,np.newaxis]; + # Save the image + Mode=["L","LA","RGB","RGBA"][Texture.shape[2]-1]+";16"; + png.from_array(Texture,Mode).save(OutputPNGFilePath); + + +def StoreNDTextureHDR(Array,OutputFilePath): + """This function stores the given unsigned integer array in a minimalist binary + file format. The last dimension is interpreted as corresponding to the + channels of the image. The file format consists of a sequence of unsigned, + least significant bit first 32-bit integers. The contained data is described + below: + - Version: File format version, should be 1. + - nChannel: The number of color channels in the image. This should be a value + between 1 (greyscale) and 4 (RGBA). + - nDimension: The number of dimensions of the stored array, i.e. the number of + indices required to uniquely identify one pixel, voxel, etc.. + - Shape[nDimension]: nDimension integers providing the size of the array along + each dimension. By convention the first dimension is height, second width + and third depth. + - Data[Shape[0]*...*Shape[nDimension-1]*nChannel]: The uncompressed data of + the array. The channels are unrolled first, followed by all dimensions in + reverse order. Thus, an RG image of size 3*2 would be stored in the + following order: 00R, 00G, 01R, 01G, 10R, 10G, 11R, 11G, 20R, 20G, 21R, + 21G""" + # Prepare all the meta data and the data itself + Array=np.asarray(Array,dtype=np.uint32); + Version=1; + nDimension=len(Array.shape)-1; + nChannel=Array.shape[nDimension]; + Shape=Array.shape[0:nDimension]; + Data=Array.flatten("C"); + # Write it to the file + OutputFile=open(OutputFilePath,"wb"); + OutputFile.write(struct.pack("LLL",Version,nChannel,nDimension)); + OutputFile.write(struct.pack("L"*nDimension,*Shape)); + OutputFile.write(struct.pack("L"*np.size(Data),*Data)); + OutputFile.close(); + + +def LoadNDTextureHDR(SourceFilePath): + """Loads a file generated by StoreNDTextureHDR() and returns it as an array like + the one that goes into StoreNDTextureHDR() using data type np.uint32. On + failure it returns None.""" + # Load the meta data + File=open(SourceFilePath,"rb"); + Version,nChannel,nDimension=struct.unpack_from("LLL",File.read(12)); + if(Version!=1): + return None; + Shape=struct.unpack_from("L"*nDimension,File.read(4*nDimension)); + nScalar=np.prod(Shape)*nChannel; + Data=struct.unpack_from("L"*nScalar,File.read(4*nScalar)); + File.close(); + # Prepare the output + return np.asarray(Data,dtype=np.uint32).reshape(tuple(list(Shape)+[nChannel]),order="C"); + + +def GenerateBlueNoiseDatabase(RandomSeedIndexList=range(1),MinResolution=16,MaxResolution=1024,ChannelCountList=[1,2,3,4],StandardDeviation=1.5): + """This function generates a database of blue noise textures for all sorts of + use cases. It includes power-of-two resolutions from MinResolution**2 up + to MaxResolution**2. Textures are generated with each given number of + channels. Each texture is generated multiple times using different random + numbers per entry in RandomSeedIndexList and the entries become part of the + file name. StandardDeviation forwards to GetVoidAndClusterBlueNoise(). The + results are stored as LDR and HDR files to a well-organized tree of + of directories.""" + Resolution=MinResolution; + while(Resolution<=MaxResolution): + OutputDirectory="../Data/%d_%d"%(Resolution,Resolution); + if(not path.exists(OutputDirectory)): + makedirs(OutputDirectory); + for nChannel in ChannelCountList: + for i in RandomSeedIndexList: + Texture=np.dstack([GetVoidAndClusterBlueNoise((Resolution,Resolution),StandardDeviation) for j in range(nChannel)]); + LDRFormat=["LLL1","RG01","RGB1","RGBA"][nChannel-1]; + HDRFormat=["L","LA","RGB","RGBA"][nChannel-1]; + StoreNoiseTextureLDR(Texture,path.join(OutputDirectory,"LDR_%s_%d.png"%(LDRFormat,i))); + StoreNoiseTextureHDR(Texture,path.join(OutputDirectory,"HDR_%s_%d.png"%(HDRFormat,i))); + print("%d*%d, %s, %d"%(Resolution,Resolution,LDRFormat,i)); + Resolution*=2; + + +def Generate3DBlueNoiseTexture(Width,Height,Depth,nChannel,StandardDeviation=1.5): + """This function generates a single 3D blue noise texture with the specified + dimensions and number of channels. It then outputs it to a sequence of Depth + output files in LDR and HDR in a well-organized tree of directories. It also + outputs raw binary files. + \sa StoreNDTextureHDR() """ + OutputDirectory="../Data/%d_%d_%d"%(Width,Height,Depth); + if(not path.exists(OutputDirectory)): + makedirs(OutputDirectory); + # Generate the blue noise for the various channels using multi-threading + ChannelTextureList=[None]*nChannel; + ChannelThreadList=[None]*nChannel; + def GenerateAndStoreTexture(Index): + ChannelTextureList[Index]=GetVoidAndClusterBlueNoise((Height,Width,Depth),StandardDeviation); + for i in range(nChannel): + ChannelThreadList[i]=threading.Thread(target=GenerateAndStoreTexture,args=(i,)); + ChannelThreadList[i].start(); + for Thread in ChannelThreadList: + Thread.join(); + Texture=np.concatenate([ChannelTextureList[i][:,:,:,np.newaxis] for i in range(nChannel)],3); + LDRFormat=["LLL1","RG01","RGB1","RGBA"][nChannel-1]; + HDRFormat=["L","LA","RGB","RGBA"][nChannel-1]; + StoreNDTextureHDR(Texture,path.join(OutputDirectory,"HDR_"+HDRFormat+".raw")); + for i in range(Depth): + StoreNoiseTextureLDR(Texture[:,:,i,:],path.join(OutputDirectory,"LDR_%s_%d.png"%(LDRFormat,i)),Height*Width*Depth); + StoreNoiseTextureHDR(Texture[:,:,i,:],path.join(OutputDirectory,"HDR_%s_%d.png"%(HDRFormat,i)),Height*Width*Depth); + + +def GenerateNDBlueNoiseTexture(Shape,nChannel,OutputFilePath,StandardDeviation=1.5): + """This function generates a single n-dimensional blue noise texture with the + specified shape and number of channels. It then outputs it to the specified + raw binary file. + \sa StoreNDTextureHDR() """ + OutputDirectory=path.split(OutputFilePath)[0]; + if(not path.exists(OutputDirectory)): + makedirs(OutputDirectory); + # Generate the blue noise for the various channels using multi-threading + ChannelTextureList=[None]*nChannel; + ChannelThreadList=[None]*nChannel; + def GenerateAndStoreTexture(Index): + ChannelTextureList[Index]=GetVoidAndClusterBlueNoise(Shape,StandardDeviation); + for i in range(nChannel): + ChannelThreadList[i]=threading.Thread(target=GenerateAndStoreTexture,args=(i,)); + ChannelThreadList[i].start(); + for Thread in ChannelThreadList: + Thread.join(); + Texture=np.concatenate([ChannelTextureList[i][...,np.newaxis] for i in range(nChannel)],len(Shape)); + StoreNDTextureHDR(Texture,OutputFilePath); + + +def UniformToTriangularDistribution(UniformTexture): + """Given an array with a uniform distribution of values, this function + constructs an array of equal shape with a triangular distribution of values. + This is accomplished by applying a differentiable, monotonously growing + function per entry. + \param UniformTexture An integer array containing each value from 0 to + np.size(UniformTexture)-1 exactly once. + \return A floating-point array with values between -1 and 1 where the density + grows linearly between -1 and 0 and falls linearly between 0 and 1.""" + Normalized=(np.asarray(UniformTexture,dtype=np.float)+0.5)/float(np.size(UniformTexture)); + return np.where(Normalized<0.5,np.sqrt(2.0*Normalized)-1.0,1.0-np.sqrt(2.0-2.0*Normalized)); + + +if(__name__=="__main__"): + #GenerateBlueNoiseDatabase(range(64),16,64,range(1,5),1.9); + #GenerateBlueNoiseDatabase(range(16),128,128,range(1,5),1.9); + #GenerateBlueNoiseDatabase(range(8),256,256,range(1,5),1.9); + #GenerateBlueNoiseDatabase(range(1),512,512,range(1,5),1.9); + #GenerateBlueNoiseDatabase(range(1),1024,1024,[4],1.9); + #for nChannel in range(1,5): + #Generate3DBlueNoiseTexture(16,16,16,nChannel,1.9); + #Generate3DBlueNoiseTexture(32,32,32,nChannel,1.9); + #Generate3DBlueNoiseTexture(64,64,64,nChannel,1.9); + #ChannelNames=["","L","LA","RGB","RGBA"][nChannel]; + #GenerateNDBlueNoiseTexture((8,8,8,8),nChannel,"../Data/8_8_8_8/HDR_"+ChannelNames+".raw",1.9); + #GenerateNDBlueNoiseTexture((16,16,16,16),nChannel,"../Data/16_16_16_16/HDR_"+ChannelNames+".raw",1.9); + Texture=GetVoidAndClusterBlueNoise((64,64),1.9); + #Texture=GetVoidAndClusterBlueNoise((32,32,32),1.9)[:,:,0]; + AnalyzeNoiseTexture(Texture,True); + PlotBinaryPatterns(Texture,3,5); + pyplot.show(); diff --git a/tools/meta-make/bluenoise/LICENSE b/tools/meta-make/bluenoise/LICENSE new file mode 100644 index 000000000..0e259d42c --- /dev/null +++ b/tools/meta-make/bluenoise/LICENSE @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/tools/meta-make/bluenoise/README.md b/tools/meta-make/bluenoise/README.md new file mode 100644 index 000000000..295a3119b --- /dev/null +++ b/tools/meta-make/bluenoise/README.md @@ -0,0 +1,5 @@ +# BlueNoise +A SciPy implementation of the void-and-cluster method for generation of blue noise textures with arbitrary dimension. + +For more information see the corresponding blog post: +http://momentsingraphics.de/?p=127 diff --git a/tools/meta-make/bluenoise/metagen-bluenoise.py b/tools/meta-make/bluenoise/metagen-bluenoise.py new file mode 100644 index 000000000..3cb164157 --- /dev/null +++ b/tools/meta-make/bluenoise/metagen-bluenoise.py @@ -0,0 +1,203 @@ +import numpy as np +import getopt, sys + +from BlueNoise import GetVoidAndClusterBlueNoise, StoreNoiseTextureLDR, StoreNoiseTextureHDR + +defaultInit = "0.1"; +defaultSigma = "1.5"; + +def printerr(s): + sys.stderr.write("%s\n" % s); + +def UsageError(): + printerr("metagen-bluenoise.py"); + printerr(" Create tiling blue noise pattern as a C-style array of integers,"); + printerr(" using a void-and-cluster algorithm."); + printerr("Usage:"); + printerr(" python metagen-bluenoise.py [options] [ []]"); + printerr("Parameters:"); + printerr(" : Identifier base name for the pattern."); + printerr(" : Width of the pattern to generate."); + printerr(" : Height of the pattern to generate."); + printerr(" : 3D slices of the pattern to generate."); + printerr("Pattern generation options:"); + printerr(" -i Initial seed fraction. Defaults to %s" % defaultInit); + printerr(" -r Random seed. Allows to re-produce patterns."); + printerr(" -s Standard deviation of filter used in pattern generation."); + printerr(" Higher values generate a coarser pattern. Defaults to %s." % defaultSigma); + printerr("Output options:"); + printerr(" -h Generates declaration only."); + printerr(" -l Generates linear array instead of 2D array."); + printerr(" -n Wraps the declaration/definition in a namespace."); + printerr(" -p Write a copy of the pattern to PNG file. Primarily intended"); + printerr(" for testing."); + sys.exit(2); + +def Error(s): + printerr(s); + sys.exit(2); + +header = False; +initStr = defaultInit; +init = float(initStr); +linear = False; +pngfile = ""; +sigmaStr = defaultSigma; +sigma = float(sigmaStr); +haveSeed = False; +namespace = ""; + +try: + opts, args = getopt.getopt(sys.argv[1:], "hi:ln:p:r:s:"); + +except getopt.GetoptError as err: + UsageError(); + +try: + for o, a in opts: + if (o == "-h"): + header = True; + elif (o == "-i"): + initStr = a; + init = float(a); + elif (o == "-l"): + linear = True; + elif (o == "-n"): + namespace = a; + elif (o == "-p"): + pngfile = a; + elif (o == "-r"): + haveSeed = True; + seed = int(a); + elif (o == "-s"): + sigmaStr = a; + sigma = float(a); + else: + Error("Unrecognized option %s" % (o, a)); + assert False, "unhandled option"; + + argcount = len(args); + if (argcount < 2): + printerr("Not enough parameters."); + UsageError(); + if (argcount > 4): + printerr("Too many parameters."); + UsageError(); + + name = args[0]; + width = int(args[1]); + if (argcount > 2): + height = int(args[2]); + else: + height = width; + if (argcount > 3): + slices = int(args[3]); + else: + slices = 0; + +except ValueError as err: + UsageError(); + +size = width * height; +if (slices == 0): + zCount = 1; +else: + zCount = slices; +size3d = size * zCount; + +if (size > 1024 * 1024): + Error("Excessively large pattern. 1024x1024 should be enough for everybody."); + +if (size3d <= 256): + type = "unsigned char"; +elif (size3d <= 65536): + type = "unsigned short"; +else: + type = "unsigned int"; + +if (size3d <= 10): + format = "%1i"; +elif (size3d <= 100): + format = "%2i"; +elif (size3d <= 1000): + format = "%3i"; +elif (size3d <= 10000): + format = "%4i"; +elif (size3d <= 100000): + format = "%5i"; +elif (size3d <= 1000000): + format = "%6i"; +elif (size3d <= 10000000): + format = "%7i"; +else: + format = "%i"; +itemsPerLine = 16; + +if (namespace): + print("namespace %s {" % namespace) + print + +if (linear): + if (slices == 0): + declaration = "extern const %s %s[%i]" % (type, name, size); + else: + declaration = "extern const %s %s[%i][%i]" % (type, name, slices, size); +else: + if (slices == 0): + declaration = "extern const %s %s[%i][%i]" % (type, name, height, width); + else: + declaration = "extern const %s %s[%i][%i][%i]" % (type, name, slices, height, width); + +if (header): + print("%s;" % declaration); +else: + if (haveSeed): + np.random.seed(seed); + if (slices == 0): + Texture=GetVoidAndClusterBlueNoise((width,height),sigma,init); + else: + Texture=GetVoidAndClusterBlueNoise((width,height,slices),sigma,init); + if (pngfile != ""): + if (size3d <= 256): + StoreNoiseTextureLDR(Texture,pngfile); + else: + StoreNoiseTextureHDR(Texture,pngfile); + print("/// %ix%i blue noise pattern data." % (width, height)); + info = "-i%s -s%s" % (initStr, sigmaStr); + if (haveSeed): + info = info + " -r%i" % seed; + print("/// Generated using `make-bluenoise.py %s`." % info); + if (slices == 0): + print("%s = {" % declaration); + else: + print("%s = {{" % declaration); + for z in range(zCount): + if ((slices != 0) and (z > 0)): + print(" },{"); + for y in range(width): + data = "" + for x in range(height): + if (x > 0): + data = data + ","; + if (x % itemsPerLine == 0): + if (linear): + data = data + "\n "; + else: + data = data + "\n "; + if (slices == 0): + value = Texture.item((x,y)); + else: + value = Texture.item((x,y,z)); + data = data + (format % value); + if (linear): + print(" %s," % data); + else: + print(" { %s }," % data); + if(slices == 0): + print(" };"); + else: + print(" }};"); + +if (namespace): + print + print("}") diff --git a/tools/meta-make/meta-make.sh b/tools/meta-make/meta-make.sh deleted file mode 100644 index 5b6814ecf..000000000 --- a/tools/meta-make/meta-make.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/bash - -# ============================================================================= - -# Print header for single C++ source file. -# $1 - output file name -# $2 - input file name -function reswrap_header { - sed "tools/meta-make/reswrap-header.cpp" \ - -e 's|{{filename}}|'"${1#source/}"'|g' \ - -e 's|{{source}}|'"${2#source/}"'|g' -} - -# Create single C++ source file. -# $1 - output file name -# $2 - input file name -# $3 - C++ namespace -# $4 - C++ identifier -# $5 - additional reswrap options -function reswrap1 { - reswrap_header "$1" "$2" > "$1" - reswrap $5 -oa "$1" -n "$3" -e -s -r "$4" "$2" -} - -# Create C++ source file pair (`.cpp`, `.h`). -# $1 - output base file name -# $2 - input file name -# $3 - C++ namespace -# $4 - C++ identifier -# $5 - additional reswrap options -function reswrap2 { - reswrap1 "$1.cpp" "$2" "$3" "$4" "$5" - reswrap1 "$1.h" "$2" "$3" "$4" "$5 -i" -} - -# Create C++ source file pair for a binary file. -# $1 - output base file name -# $2 - input file name -# $3 - C++ namespace -# $4 - C++ identifier -function reswrap_binary { - reswrap2 "$@" "-z" -} - -# Create C++ source file pair for a text file. -# $1 - output base file name -# $2 - input file name -# $3 - C++ namespace -# $4 - C++ identifier -function reswrap_text { - reswrap2 "$@" "-m -ta -c 120" -} - -# Create C++ source file pair for a TTF font file. -# $1 - font base file name -function reswrap_ttf { - reswrap_binary "source/base/font/$1" "distribution/include/$1.ttf" "pov_base" "font_$1" -} - -# Create C++ source file pair for a benchmark-related file. -# $1 - file type ("pov" or "ini") -# $2 - C++ identifier -function reswrap_benchmark { - reswrap_text "source/backend/control/benchmark_$1" "distribution/scenes/advanced/benchmark/benchmark.$1" "pov" "$2" -} - -# ============================================================================= - -# TrueType Fonts - -reswrap_ttf "crystal" -reswrap_ttf "cyrvetic" -reswrap_ttf "povlogo" -reswrap_ttf "timrom" - -# Benchmark Scene - -reswrap_benchmark "pov" "Benchmark_File" -reswrap_benchmark "ini" "Benchmark_Options" diff --git a/tools/meta-make/metagen-header.cpp b/tools/meta-make/metagen-header.cpp new file mode 100644 index 000000000..c60deb231 --- /dev/null +++ b/tools/meta-make/metagen-header.cpp @@ -0,0 +1,43 @@ +//****************************************************************************** +/// +/// @file {{filename}} +/// +/// {{info}} +/// Auto-generated using {{generator}}. +/// +/// @copyright +/// @parblock +/// +/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. +/// Copyright 1991-{{year}} Persistence of Vision Raytracer Pty. Ltd. +/// +/// POV-Ray is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as +/// published by the Free Software Foundation, either version 3 of the +/// License, or (at your option) any later version. +/// +/// POV-Ray is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// You should have received a copy of the GNU Affero General Public License +/// along with this program. If not, see . +/// +/// ---------------------------------------------------------------------------- +/// +/// POV-Ray is based on the popular DKB raytracer version 2.12. +/// DKBTrace was originally written by David K. Buck. +/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. +/// +/// @endparblock +/// +//****************************************************************************** + +/// @file +/// @attention +/// **DO NOT EDIT THIS FILE!** +/// Instead, if this file needs fixing, modify {{generator}} +/// or its invocation in `tools/meta-make/Makefile` accordingly, +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). + diff --git a/tools/meta-make/metagen.sh b/tools/meta-make/metagen.sh new file mode 100644 index 000000000..ad2b74e6f --- /dev/null +++ b/tools/meta-make/metagen.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# $1 - full output file name +# $2 - info +# $3 - generator tool command +# $4 - generator tool parameters +# $5 - include file extra parameters + +echo $1 + +filename="${1#../../source/}" +info="$2" +generator="${3##* }" +generator="${generator##*/}" + +if [ "${filename##*.}" == "h" ]; then + opts="$5" +else + opts="" +fi + +sed "metagen-header.cpp" \ + -e 's|{{filename}}|'"$filename"'|g' \ + -e 's|{{info}}|'"$info"'|g' \ + -e 's|{{generator}}|'"$generator"'|g' \ + -e 's|{{year}}|'`date +"%Y"`'|g' > "$1" || exit 2 + +$3 $opts $4 >> "$1" && exit 0 + +rm "$1" +exit 2 diff --git a/tools/meta-make/readme.md b/tools/meta-make/readme.md index 386d158d0..3b51cb76e 100644 --- a/tools/meta-make/readme.md +++ b/tools/meta-make/readme.md @@ -13,15 +13,25 @@ packages installed (or a compatible environment): - `bash` - `libfox-1.6-dev` (we expect other versions to work as well) + - `python`, `python-numpy`, `python-scipy`, `python-matplotlib`, `python-pypng` Procedure ========= -Invoke the following command from the root directory of the POV-Ray source package: +From the root of the POV-Ray source package, change to the `tools/meta-make` +directory, and invoke the following command: - tools/meta-make/meta-make.sh + make + +This will re-create all missing or outdated generated files. + +To re-create all converted files unconditionally, use: + + make clean all + +Note that some files may take a while to re-create. Output @@ -31,6 +41,7 @@ The following files will be re-created: | Generated File | Generated From | |:--------------------------------------------------|:----------------------------------------------------------| +| `source/base/data/bluenoise*.cpp`/`.h` | `tools/meta-make/bluenoise/metagen-bluenoise.py` | | `source/base/font/crystal.cpp`/`.h` | `distribution/include/crystal.ttf` | | `source/base/font/cyrvetic.cpp`/`.h` | `distribution/include/cyrvetic.ttf` | | `source/base/font/povlogo.cpp`/`.h` | `distribution/include/povlogo.ttf` | diff --git a/tools/meta-make/reswrap-header.cpp b/tools/meta-make/reswrap-header.cpp index b59f146f5..eba32fdb7 100644 --- a/tools/meta-make/reswrap-header.cpp +++ b/tools/meta-make/reswrap-header.cpp @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-{{year}} Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -37,5 +37,5 @@ /// @attention /// **DO NOT EDIT THIS FILE!** /// Instead, edit `{{source}}`, -/// and re-generate this file as described in `tools/meta-make/readme.md`. +/// and re-generate this file as described in @ref tools-metamake (`tools/meta-make/readme.md`). diff --git a/tools/meta-make/reswrap.sh b/tools/meta-make/reswrap.sh new file mode 100644 index 000000000..707c0aefd --- /dev/null +++ b/tools/meta-make/reswrap.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# $1 - full output file name +# $2 - full source file name +# $3 - namespace +# $4 - identifier +# $5 - additional options + +echo $1 + +filename="${1#../../source/}" +source="${2#../../}" + +if [ "${filename##*.}" == "h" ]; then + opts="-i" +else + opts="" +fi + +sed "reswrap-header.cpp" \ + -e 's|{{filename}}|'"$filename"'|g' \ + -e 's|{{source}}|'"$source"'|g' \ + -e 's|{{year}}|'`date +"%Y"`'|g' > "$1" || exit 2 + +reswrap $opts $5 -oa "$1" -n "$3" -e -s -r "$4" "$2" && exit 0 + +rm "$1" +exit 2 diff --git a/unix/disp.h b/unix/disp.h index 2306090aa..b01178119 100644 --- a/unix/disp.h +++ b/unix/disp.h @@ -41,8 +41,6 @@ #include "vfe.h" -#include - namespace pov_frontend { using namespace vfe; @@ -52,8 +50,8 @@ namespace pov_frontend class UnixDisplay : public vfeDisplay { public: - UnixDisplay(unsigned int w, unsigned int h, GammaCurvePtr gamma, vfeSession *session, bool visible) : - vfeDisplay(w, h, gamma, session, visible) {}; + UnixDisplay(unsigned int w, unsigned int h, vfeSession *session, bool visible) : + vfeDisplay(w, h, session, visible) {}; virtual ~UnixDisplay() {} ; virtual void Initialise() = 0; virtual void Close() = 0; diff --git a/unix/disp_sdl.cpp b/unix/disp_sdl.cpp index 00907494e..a1d8a0539 100644 --- a/unix/disp_sdl.cpp +++ b/unix/disp_sdl.cpp @@ -69,8 +69,8 @@ namespace pov_frontend return true; } - UnixSDLDisplay::UnixSDLDisplay(unsigned int w, unsigned int h, GammaCurvePtr gamma, vfeSession *session, bool visible) : - UnixDisplay(w, h, gamma, session, visible) + UnixSDLDisplay::UnixSDLDisplay(unsigned int w, unsigned int h, vfeSession *session, bool visible) : + UnixDisplay(w, h, session, visible) { m_valid = false; m_display_scaled = false; diff --git a/unix/disp_sdl.h b/unix/disp_sdl.h index a0639a540..dbbfe2742 100644 --- a/unix/disp_sdl.h +++ b/unix/disp_sdl.h @@ -10,7 +10,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -57,7 +57,7 @@ namespace pov_frontend static const UnixOptionsProcessor::Option_Info Options[]; static bool Register(vfeUnixSession *session); - UnixSDLDisplay(unsigned int w, unsigned int h, GammaCurvePtr gamma, vfeSession *session, bool visible); + UnixSDLDisplay(unsigned int w, unsigned int h, vfeSession *session, bool visible); virtual ~UnixSDLDisplay(); void Initialise(); void Close(); diff --git a/unix/disp_text.h b/unix/disp_text.h index d24dc9806..bce8af57e 100644 --- a/unix/disp_text.h +++ b/unix/disp_text.h @@ -10,7 +10,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -53,8 +53,8 @@ namespace pov_frontend static const UnixOptionsProcessor::Option_Info Options[]; static bool Register(vfeUnixSession *session); - UnixTextDisplay(unsigned int w, unsigned int h, GammaCurvePtr gamma, vfeSession *session, bool visible) : - UnixDisplay(w, h, gamma, session, visible) {}; + UnixTextDisplay(unsigned int w, unsigned int h, vfeSession *session, bool visible) : + UnixDisplay(w, h, session, visible) {}; virtual ~UnixTextDisplay() {} ; void Initialise() {}; void Close() {}; diff --git a/vfe/unix/unixconsole.cpp b/vfe/unix/unixconsole.cpp index cd7337358..f35a283a9 100644 --- a/vfe/unix/unixconsole.cpp +++ b/vfe/unix/unixconsole.cpp @@ -37,9 +37,6 @@ #include #include -// Boost header files -#include - // Other library header files #include #include @@ -147,7 +144,7 @@ static void ProcessSignal (void) gSignalNumber = 0; } -static vfeDisplay *UnixDisplayCreator (unsigned int width, unsigned int height, GammaCurvePtr gamma, vfeSession *session, bool visible) +static vfeDisplay *UnixDisplayCreator (unsigned int width, unsigned int height, vfeSession *session, bool visible) { UnixDisplay *display = GetRenderWindow () ; switch (gDisplayMode) @@ -156,16 +153,16 @@ static vfeDisplay *UnixDisplayCreator (unsigned int width, unsigned int height, case DISP_MODE_SDL: if (display != nullptr && display->GetWidth() == width && display->GetHeight() == height) { - UnixDisplay *p = new UnixSDLDisplay (width, height, gamma, session, false) ; + UnixDisplay *p = new UnixSDLDisplay (width, height, session, false) ; if (p->TakeOver (display)) return p; delete p; } - return new UnixSDLDisplay (width, height, gamma, session, visible) ; + return new UnixSDLDisplay (width, height, session, visible) ; break; #endif case DISP_MODE_TEXT: - return new UnixTextDisplay (width, height, gamma, session, visible) ; + return new UnixTextDisplay (width, height, session, visible) ; break; default: return nullptr; diff --git a/vfe/vfe.cpp b/vfe/vfe.cpp index cc09019b9..e02c528a1 100644 --- a/vfe/vfe.cpp +++ b/vfe/vfe.cpp @@ -1096,7 +1096,7 @@ State VirtualFrontEnd::Process() // case. return state; } - try { viewId = renderFrontend.CreateView(sceneId, options, imageProcessing, boost::bind(&vfe::VirtualFrontEnd::CreateDisplay, this, _1, _2, _3)); } + try { viewId = renderFrontend.CreateView(sceneId, options, imageProcessing, boost::bind(&vfe::VirtualFrontEnd::CreateDisplay, this, _1, _2)); } catch(pov_base::Exception& e) { m_Session->SetFailed(); diff --git a/vfe/vfe.h b/vfe/vfe.h index c9fc94f96..f3ca10708 100644 --- a/vfe/vfe.h +++ b/vfe/vfe.h @@ -10,7 +10,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -49,7 +49,6 @@ #include "base/platformbase.h" #include "base/timer.h" -#include "base/image/colourspace.h" #include "frontend/console.h" #include "frontend/display.h" @@ -197,7 +196,7 @@ namespace vfe class vfeDisplay : public Display { public: - vfeDisplay(unsigned int width, unsigned int height, GammaCurvePtr gamma, vfeSession *session, bool visible = false); + vfeDisplay(unsigned int width, unsigned int height, vfeSession *session, bool visible = false); virtual ~vfeDisplay(); virtual void Initialise(); @@ -240,8 +239,8 @@ namespace vfe protected: virtual Console *CreateConsole() { return new vfeConsole(m_Session, m_Session->GetConsoleWidth()); } - virtual Display *CreateDisplay(unsigned int width, unsigned int height, GammaCurvePtr gamma) - { return m_Session->CreateDisplay(width, height, gamma) ; } + virtual Display *CreateDisplay(unsigned int width, unsigned int height) + { return m_Session->CreateDisplay(width, height) ; } bool HandleShelloutCancel(); RenderFrontend renderFrontend; diff --git a/vfe/vfedisplay.cpp b/vfe/vfedisplay.cpp index 2dd1d7fba..fdf59bc4d 100644 --- a/vfe/vfedisplay.cpp +++ b/vfe/vfedisplay.cpp @@ -10,7 +10,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -50,8 +50,8 @@ namespace vfe { -vfeDisplay::vfeDisplay(unsigned int w, unsigned int h, GammaCurvePtr gamma, vfeSession* session, bool visible) : - Display(w, h, gamma), +vfeDisplay::vfeDisplay(unsigned int w, unsigned int h, vfeSession* session, bool visible) : + Display(w, h), m_Session(session), m_VisibleOnCreation(visible) { diff --git a/vfe/vfesession.cpp b/vfe/vfesession.cpp index 1ad005d61..2a5c79603 100644 --- a/vfe/vfesession.cpp +++ b/vfe/vfesession.cpp @@ -78,7 +78,7 @@ vfeSession::vfeSession(int id) m_RequestFlag = rqNoRequest; m_RequestResult = 0; m_StartTime = 0; - m_DisplayCreator = boost::bind(&vfe::vfeSession::DefaultDisplayCreator, this, _1, _2, _3, _4, _5); + m_DisplayCreator = boost::bind(&vfe::vfeSession::DefaultDisplayCreator, this, _1, _2, _3, _4); Reset(); } @@ -737,9 +737,9 @@ vfeSession *vfeSession::GetSessionFromThreadID() return m_CurrentSessionTemporaryHack ; } -vfeDisplay *vfeSession::DefaultDisplayCreator (unsigned int width, unsigned int height, GammaCurvePtr gamma, vfeSession *session, bool visible) +vfeDisplay *vfeSession::DefaultDisplayCreator (unsigned int width, unsigned int height, vfeSession *session, bool visible) { - return new vfeDisplay (width, height, gamma, session, visible) ; + return new vfeDisplay (width, height, session, visible) ; } // If a VFE implementation has provided the address of a display creator @@ -750,9 +750,9 @@ vfeDisplay *vfeSession::DefaultDisplayCreator (unsigned int width, unsigned int // If a display instance is returned, it is expected to conform to the // definition of the pov_frontend::Display class, but will typically be // a platform-specific derivative of that. -vfeDisplay *vfeSession::CreateDisplay (unsigned int width, unsigned int height, GammaCurvePtr gamma, bool visible) +vfeDisplay *vfeSession::CreateDisplay (unsigned int width, unsigned int height, bool visible) { - return m_DisplayCreator (width, height, gamma, this, visible); + return m_DisplayCreator (width, height, this, visible); } // This method causes a shutdown of the vfeSession instance. Specifically diff --git a/vfe/vfesession.h b/vfe/vfesession.h index 68f6441c5..e5a4c0988 100644 --- a/vfe/vfesession.h +++ b/vfe/vfesession.h @@ -44,8 +44,6 @@ #include #include -#include "base/image/colourspace.h" - #include "frontend/simplefrontend.h" namespace pov_frontend @@ -358,7 +356,7 @@ namespace vfe public: // Our DisplayCreator functor - see vfeSession::SetDisplayCreator(). - typedef boost::function DisplayCreator; + typedef boost::function DisplayCreator; typedef enum { mUnclassified = 0, @@ -542,7 +540,7 @@ namespace vfe // window be created. The display instance returned is expected to conform // to the definition of the pov_frontend::Display class (but it typically // a platform-specific derivative of that.) - virtual vfeDisplay *CreateDisplay(unsigned int width, unsigned int height, GammaCurvePtr gamma, bool visible = false); + virtual vfeDisplay *CreateDisplay(unsigned int width, unsigned int height, bool visible = false); // Used by VFE implementations to allow their own custom pov_frontend::Display // derived render preview window class to be created when the main POV-Ray code @@ -1258,7 +1256,7 @@ namespace vfe static vfeSession *m_CurrentSessionTemporaryHack; shared_ptr m_Console; - virtual vfeDisplay *DefaultDisplayCreator (unsigned int width, unsigned int height, GammaCurvePtr gamma, vfeSession *session, bool visible); + virtual vfeDisplay *DefaultDisplayCreator (unsigned int width, unsigned int height, vfeSession *session, bool visible); DisplayCreator m_DisplayCreator; int m_MaxStatusMessages; diff --git a/windows/pvdisplay.cpp b/windows/pvdisplay.cpp index 81b9b06a2..99fe17f52 100644 --- a/windows/pvdisplay.cpp +++ b/windows/pvdisplay.cpp @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -116,8 +116,8 @@ shared_ptr gDisplay; BitmapInfo WinLegacyDisplay::m_BitmapTemplate; -WinLegacyDisplay::WinLegacyDisplay(unsigned int w, unsigned int h, GammaCurvePtr gamma, vfeSession *session, bool visible) : - WinDisplay(w, h, gamma, session, visible) +WinLegacyDisplay::WinLegacyDisplay(unsigned int w, unsigned int h, vfeSession *session, bool visible) : + WinDisplay(w, h, session, visible) { m_BitmapSurface = NULL; m_LastY = 0; diff --git a/windows/pvdisplay.h b/windows/pvdisplay.h index 97e78f2b7..1caf990c1 100644 --- a/windows/pvdisplay.h +++ b/windows/pvdisplay.h @@ -8,7 +8,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -51,8 +51,8 @@ namespace pov_frontend class WinDisplay : public vfeDisplay { public: - WinDisplay(unsigned int w, unsigned int h, GammaCurvePtr gamma, vfeSession *session, bool visible) : - vfeDisplay(w, h, gamma, session, visible), m_Handle (NULL) {}; + WinDisplay(unsigned int w, unsigned int h, vfeSession *session, bool visible) : + vfeDisplay(w, h, session, visible), m_Handle (NULL) {}; virtual ~WinDisplay() {} ; virtual bool CreateRenderWindow (void) = 0; virtual void Close() = 0; @@ -73,7 +73,7 @@ namespace pov_frontend class WinLegacyDisplay : public WinDisplay { public: - WinLegacyDisplay(unsigned int w, unsigned int h, GammaCurvePtr gamma, vfeSession *session, bool visible); + WinLegacyDisplay(unsigned int w, unsigned int h, vfeSession *session, bool visible); virtual ~WinLegacyDisplay(); void Initialise(); diff --git a/windows/pvfrontend.cpp b/windows/pvfrontend.cpp index 98ab1af52..115d8c44a 100644 --- a/windows/pvfrontend.cpp +++ b/windows/pvfrontend.cpp @@ -10,7 +10,7 @@ /// @parblock /// /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8. -/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd. +/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd. /// /// POV-Ray is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License as @@ -82,7 +82,7 @@ static vfeWinSession *gSession; // Whenever the core POV code wants to create an output window, the below code // will therefore be executed. ////////////////////////////////////////////////////////////////////////////// -vfeDisplay *WinDisplayCreator (unsigned int width, unsigned int height, GammaCurvePtr gamma, vfeSession *session, bool visible) +vfeDisplay *WinDisplayCreator (unsigned int width, unsigned int height, vfeSession *session, bool visible) { // we attempt to minimize 'flashing' of the window (destroy followed by a re-create) // by checking to see if the previous window (if any) had the same dimensions. if it @@ -92,7 +92,7 @@ vfeDisplay *WinDisplayCreator (unsigned int width, unsigned int height, GammaCur if (display != NULL && display->GetWidth() == width && display->GetHeight() == height) { WinDisplay *p ; - p = new WinLegacyDisplay (width, height, gamma, session, false) ; + p = new WinLegacyDisplay (width, height, session, false); if (p->TakeOver (display)) { bool anim = gSession->RenderingAnimation(); @@ -105,7 +105,7 @@ vfeDisplay *WinDisplayCreator (unsigned int width, unsigned int height, GammaCur } delete p; } - return new WinLegacyDisplay (width, height, gamma, session, visible) ; + return new WinLegacyDisplay (width, height, session, visible); } ////////////////////////////////////////////////////////////////////////////// diff --git a/windows/vs2015/povbase.vcxproj b/windows/vs2015/povbase.vcxproj index c69e4c616..a33b03591 100644 --- a/windows/vs2015/povbase.vcxproj +++ b/windows/vs2015/povbase.vcxproj @@ -386,12 +386,14 @@ + + @@ -446,12 +448,14 @@ + + diff --git a/windows/vs2015/povbase.vcxproj.filters b/windows/vs2015/povbase.vcxproj.filters index fc762e827..1f241f597 100644 --- a/windows/vs2015/povbase.vcxproj.filters +++ b/windows/vs2015/povbase.vcxproj.filters @@ -25,6 +25,12 @@ {9f44d3c5-81d8-4017-a1b7-5a6f9a139e28} + + {32531c25-b41d-42b5-88a0-77de8a8daa8d} + + + {b3ceef1f-ae95-40ac-b0b3-904569e9595b} + @@ -132,6 +138,12 @@ Base source + + Base source\Data + + + Base source\Image + @@ -266,5 +278,11 @@ Base Headers + + Base Headers\Data + + + Base Headers\Image + \ No newline at end of file