From 1f5fb7b33b2db66984be3e6ef1dbd47111909512 Mon Sep 17 00:00:00 2001 From: George Reales Date: Tue, 21 Jul 2020 09:33:44 +0200 Subject: [PATCH] Remove GIN module --- Modules/gin/3rdparty/avir/LICENSE | 26 - Modules/gin/3rdparty/avir/README.md | 330 - Modules/gin/3rdparty/avir/avir.h | 6198 ----------------- Modules/gin/3rdparty/avir/avir_dil.h | 1012 --- Modules/gin/3rdparty/avir/avir_float4_sse.h | 319 - Modules/gin/3rdparty/avir/avir_float8_avx.h | 359 - Modules/gin/3rdparty/muParser/muParser.cpp | 397 -- Modules/gin/3rdparty/muParser/muParser.h | 114 - .../gin/3rdparty/muParser/muParserBase.cpp | 1805 ----- Modules/gin/3rdparty/muParser/muParserBase.h | 324 - .../3rdparty/muParser/muParserBytecode.cpp | 604 -- .../gin/3rdparty/muParser/muParserBytecode.h | 143 - .../3rdparty/muParser/muParserCallback.cpp | 497 -- .../gin/3rdparty/muParser/muParserCallback.h | 119 - Modules/gin/3rdparty/muParser/muParserDef.h | 372 - .../gin/3rdparty/muParser/muParserError.cpp | 345 - Modules/gin/3rdparty/muParser/muParserError.h | 175 - Modules/gin/3rdparty/muParser/muParserFixes.h | 60 - Modules/gin/3rdparty/muParser/muParserStack.h | 125 - .../3rdparty/muParser/muParserTemplateMagic.h | 113 - Modules/gin/3rdparty/muParser/muParserToken.h | 406 -- .../3rdparty/muParser/muParserTokenReader.cpp | 982 --- .../3rdparty/muParser/muParserTokenReader.h | 159 - Modules/gin/README.md | 2 - Modules/gin/components/componentutils.h | 20 - Modules/gin/components/componentviewer.cpp | 364 - Modules/gin/components/componentviewer.h | 47 - Modules/gin/components/ginlookandfeel.cpp | 193 - Modules/gin/components/ginlookandfeel.h | 41 - Modules/gin/components/mapviewer.cpp | 165 - Modules/gin/components/mapviewer.h | 62 - Modules/gin/components/propertycomponents.cpp | 8 - Modules/gin/components/propertycomponents.h | 154 - .../gin/components/singlelinetexteditor.cpp | 2214 ------ Modules/gin/components/singlelinetexteditor.h | 617 -- Modules/gin/geometry/geometry.h | 112 - Modules/gin/gin.cpp | 134 - Modules/gin/gin.h | 106 - Modules/gin/gin.mm | 9 - Modules/gin/images/bmpimageformat.cpp | 153 - Modules/gin/images/bmpimageformat.h | 28 - Modules/gin/images/imageeffects.cpp | 811 --- Modules/gin/images/imageeffects.h | 117 - Modules/gin/images/imageeffects_blending.cpp | 282 - Modules/gin/images/imageeffects_stackblur.cpp | 717 -- Modules/gin/images/imageutilities.cpp | 23 - Modules/gin/images/imageutilities.h | 10 - Modules/gin/utilities/asyncutilities.cpp | 32 - Modules/gin/utilities/asyncutilities.h | 40 - Modules/gin/utilities/coalescedtimer.h | 89 - Modules/gin/utilities/downloadmanager.cpp | 308 - Modules/gin/utilities/downloadmanager.h | 162 - Modules/gin/utilities/easing.h | 289 - Modules/gin/utilities/elevatedfilecopy.cpp | 354 - Modules/gin/utilities/elevatedfilecopy.h | 82 - Modules/gin/utilities/equationparser.cpp | 233 - Modules/gin/utilities/equationparser.h | 52 - Modules/gin/utilities/filesystemwatcher.cpp | 329 - Modules/gin/utilities/filesystemwatcher.h | 93 - Modules/gin/utilities/fileutilities.cpp | 43 - Modules/gin/utilities/fileutilities.h | 23 - Modules/gin/utilities/integrator.cpp | 45 - Modules/gin/utilities/integrator.h | 31 - Modules/gin/utilities/lagrange.h | 70 - .../gin/utilities/leastsquaresregression.cpp | 266 - .../gin/utilities/leastsquaresregression.h | 53 - Modules/gin/utilities/linearregression.cpp | 68 - Modules/gin/utilities/linearregression.h | 49 - Modules/gin/utilities/messagepack.cpp | 442 -- Modules/gin/utilities/messagepack.h | 27 - Modules/gin/utilities/openstreetmaps.cpp | 253 - Modules/gin/utilities/openstreetmaps.h | 100 - Modules/gin/utilities/plist.cpp | 110 - Modules/gin/utilities/plist.h | 16 - .../gin/utilities/realtimeasyncupdater.cpp | 131 - Modules/gin/utilities/realtimeasyncupdater.h | 36 - Modules/gin/utilities/sharedmemory.cpp | 160 - Modules/gin/utilities/sharedmemory.h | 37 - Modules/gin/utilities/spline.cpp | 78 - Modules/gin/utilities/spline.h | 47 - Modules/gin/utilities/systemsemaphore.cpp | 110 - Modules/gin/utilities/systemsemaphore.h | 29 - Modules/gin/utilities/threading.cpp | 43 - Modules/gin/utilities/threading.h | 48 - Modules/gin/utilities/util.cpp | 52 - Modules/gin/utilities/util.h | 267 - Modules/gin/utilities/valuetreeobject.cpp | 70 - Modules/gin/utilities/valuetreeobject.h | 97 - Modules/gin/utilities/valuetreeutilities.cpp | 93 - Modules/gin/utilities/valuetreeutilities.h | 173 - 90 files changed, 26503 deletions(-) delete mode 100755 Modules/gin/3rdparty/avir/LICENSE delete mode 100755 Modules/gin/3rdparty/avir/README.md delete mode 100755 Modules/gin/3rdparty/avir/avir.h delete mode 100755 Modules/gin/3rdparty/avir/avir_dil.h delete mode 100755 Modules/gin/3rdparty/avir/avir_float4_sse.h delete mode 100755 Modules/gin/3rdparty/avir/avir_float8_avx.h delete mode 100755 Modules/gin/3rdparty/muParser/muParser.cpp delete mode 100755 Modules/gin/3rdparty/muParser/muParser.h delete mode 100755 Modules/gin/3rdparty/muParser/muParserBase.cpp delete mode 100755 Modules/gin/3rdparty/muParser/muParserBase.h delete mode 100755 Modules/gin/3rdparty/muParser/muParserBytecode.cpp delete mode 100755 Modules/gin/3rdparty/muParser/muParserBytecode.h delete mode 100755 Modules/gin/3rdparty/muParser/muParserCallback.cpp delete mode 100755 Modules/gin/3rdparty/muParser/muParserCallback.h delete mode 100755 Modules/gin/3rdparty/muParser/muParserDef.h delete mode 100755 Modules/gin/3rdparty/muParser/muParserError.cpp delete mode 100755 Modules/gin/3rdparty/muParser/muParserError.h delete mode 100755 Modules/gin/3rdparty/muParser/muParserFixes.h delete mode 100755 Modules/gin/3rdparty/muParser/muParserStack.h delete mode 100755 Modules/gin/3rdparty/muParser/muParserTemplateMagic.h delete mode 100755 Modules/gin/3rdparty/muParser/muParserToken.h delete mode 100755 Modules/gin/3rdparty/muParser/muParserTokenReader.cpp delete mode 100755 Modules/gin/3rdparty/muParser/muParserTokenReader.h delete mode 100755 Modules/gin/README.md delete mode 100755 Modules/gin/components/componentutils.h delete mode 100755 Modules/gin/components/componentviewer.cpp delete mode 100755 Modules/gin/components/componentviewer.h delete mode 100755 Modules/gin/components/ginlookandfeel.cpp delete mode 100755 Modules/gin/components/ginlookandfeel.h delete mode 100755 Modules/gin/components/mapviewer.cpp delete mode 100755 Modules/gin/components/mapviewer.h delete mode 100755 Modules/gin/components/propertycomponents.cpp delete mode 100755 Modules/gin/components/propertycomponents.h delete mode 100755 Modules/gin/components/singlelinetexteditor.cpp delete mode 100755 Modules/gin/components/singlelinetexteditor.h delete mode 100755 Modules/gin/geometry/geometry.h delete mode 100755 Modules/gin/gin.cpp delete mode 100755 Modules/gin/gin.h delete mode 100755 Modules/gin/gin.mm delete mode 100755 Modules/gin/images/bmpimageformat.cpp delete mode 100755 Modules/gin/images/bmpimageformat.h delete mode 100755 Modules/gin/images/imageeffects.cpp delete mode 100755 Modules/gin/images/imageeffects.h delete mode 100755 Modules/gin/images/imageeffects_blending.cpp delete mode 100755 Modules/gin/images/imageeffects_stackblur.cpp delete mode 100755 Modules/gin/images/imageutilities.cpp delete mode 100755 Modules/gin/images/imageutilities.h delete mode 100755 Modules/gin/utilities/asyncutilities.cpp delete mode 100755 Modules/gin/utilities/asyncutilities.h delete mode 100755 Modules/gin/utilities/coalescedtimer.h delete mode 100755 Modules/gin/utilities/downloadmanager.cpp delete mode 100755 Modules/gin/utilities/downloadmanager.h delete mode 100755 Modules/gin/utilities/easing.h delete mode 100755 Modules/gin/utilities/elevatedfilecopy.cpp delete mode 100755 Modules/gin/utilities/elevatedfilecopy.h delete mode 100755 Modules/gin/utilities/equationparser.cpp delete mode 100755 Modules/gin/utilities/equationparser.h delete mode 100755 Modules/gin/utilities/filesystemwatcher.cpp delete mode 100755 Modules/gin/utilities/filesystemwatcher.h delete mode 100755 Modules/gin/utilities/fileutilities.cpp delete mode 100755 Modules/gin/utilities/fileutilities.h delete mode 100755 Modules/gin/utilities/integrator.cpp delete mode 100755 Modules/gin/utilities/integrator.h delete mode 100755 Modules/gin/utilities/lagrange.h delete mode 100755 Modules/gin/utilities/leastsquaresregression.cpp delete mode 100755 Modules/gin/utilities/leastsquaresregression.h delete mode 100755 Modules/gin/utilities/linearregression.cpp delete mode 100755 Modules/gin/utilities/linearregression.h delete mode 100755 Modules/gin/utilities/messagepack.cpp delete mode 100755 Modules/gin/utilities/messagepack.h delete mode 100755 Modules/gin/utilities/openstreetmaps.cpp delete mode 100755 Modules/gin/utilities/openstreetmaps.h delete mode 100755 Modules/gin/utilities/plist.cpp delete mode 100755 Modules/gin/utilities/plist.h delete mode 100755 Modules/gin/utilities/realtimeasyncupdater.cpp delete mode 100755 Modules/gin/utilities/realtimeasyncupdater.h delete mode 100755 Modules/gin/utilities/sharedmemory.cpp delete mode 100755 Modules/gin/utilities/sharedmemory.h delete mode 100755 Modules/gin/utilities/spline.cpp delete mode 100755 Modules/gin/utilities/spline.h delete mode 100755 Modules/gin/utilities/systemsemaphore.cpp delete mode 100755 Modules/gin/utilities/systemsemaphore.h delete mode 100755 Modules/gin/utilities/threading.cpp delete mode 100755 Modules/gin/utilities/threading.h delete mode 100755 Modules/gin/utilities/util.cpp delete mode 100755 Modules/gin/utilities/util.h delete mode 100755 Modules/gin/utilities/valuetreeobject.cpp delete mode 100755 Modules/gin/utilities/valuetreeobject.h delete mode 100755 Modules/gin/utilities/valuetreeutilities.cpp delete mode 100755 Modules/gin/utilities/valuetreeutilities.h diff --git a/Modules/gin/3rdparty/avir/LICENSE b/Modules/gin/3rdparty/avir/LICENSE deleted file mode 100755 index 19aecd7..0000000 --- a/Modules/gin/3rdparty/avir/LICENSE +++ /dev/null @@ -1,26 +0,0 @@ -AVIR License Agreement - -The MIT License (MIT) - -AVIR Copyright (c) 2015-2019 Aleksey Vaneev - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -Please credit the author of this library in your documentation in the -following way: "AVIR image resizing algorithm designed by Aleksey Vaneev" diff --git a/Modules/gin/3rdparty/avir/README.md b/Modules/gin/3rdparty/avir/README.md deleted file mode 100755 index 87528bc..0000000 --- a/Modules/gin/3rdparty/avir/README.md +++ /dev/null @@ -1,330 +0,0 @@ -# AVIR # -## Introduction ## -Me, Aleksey Vaneev, is happy to offer you an open source image resizing / -scaling library which has reached a production level of quality, and is -ready to be incorporated into any project. This library features routines -for both down- and upsizing of 8- and 16-bit, 1 to 4-channel images. Image -resizing routines were implemented in multi-platform C++ code, and have a -high level of optimality. Beside resizing, this library offers a sub-pixel -shift operation. Built-in sRGB gamma correction is available. - -The resizing algorithm at first produces 2X upsized image (relative to the -source image size, or relative to the destination image size if downsizing is -performed) and then performs interpolation using a bank of sinc function-based -fractional delay filters. At the last stage a correction filter is applied -which fixes smoothing introduced at previous steps. - -The resizing algorithm was designed to provide the best visual quality. The -author even believes this algorithm provides the "ultimate" level of -quality (for an orthogonal resizing) which cannot be increased further: no -math exists to provide a better frequency response, better anti-aliasing -quality and at the same time having less ringing artifacts: these are 3 -elements that define any resizing algorithm's quality; in AVIR practice these -elements have a high correlation to each other, so they can be represented by -a single parameter (AVIR offers several parameter sets with varying quality). -Algorithm's time performance turned out to be very good as well (for the -"ultimate" image quality). - -An important element utilized by this algorithm is the so called Peaked Cosine -window function, which is applied over sinc function in all filters. Please -consult the documentation for more details. - -Note that since AVIR implements orthogonal resizing, it may exhibit diagonal -aliasing artifacts. These artifacts are usually suppressed by EWA or radial -filtering techniques. EWA-like technique is not implemented in AVIR, because -it requires considerably more computing resources and may produce a blurred -image. - -AVIR does not offer affine and non-linear image transformations "out of the -box". Since upsizing is a relatively fast operation in AVIR (required time -scales linearly with the output image area), affine and non-linear -transformations can be implemented in steps: 4- to 8-times upsizing, -transformation via bilinear interpolation, downsizing (linear proportional -affine transformations can probably skip the downsizing step). This should not -compromise the transformation quality much as bilinear interpolation's -problems will mostly reside in spectral area without useful signal, with a -maximum of 0.7 dB high-frequency attenuation for 4-times upsizing, and 0.17 dB -attenuation for 8-times upsizing. This approach is probably as time efficient -as performing a high-quality transform over the input image directly (the only -serious drawback is the increased memory requirement). Note that affine -transformations that change image proportions should first apply proportion -change during upsizing. - -*AVIR is devoted to women. Your digital photos can look good at any size!* - -## Requirements ## -C++ compiler and system with efficient "float" floating point (24-bit -mantissa) type support. This library can also internally use the "double" and -SIMD floating point types during resizing if needed. This library does not -have dependencies beside the standard C library. - -## Links ## -* [Documentation](https://www.voxengo.com/public/avir/Documentation/) - -## Usage Information ## -The image resizer is represented by the `avir::CImageResizer<>` class, which -is a single front-end class for the whole library. Basically, you do not need -to use nor understand any other classes beside this class. - -The code of the library resides in the "avir" C++ namespace, effectively -isolating it from all other code. The code is thread-safe. You need just -a single resizer object per running application, at any time, even when -resizing images concurrently. - -To resize images in your application, simply add 3 lines of code: - - #include "avir.h" - avir :: CImageResizer<> ImageResizer( 8 ); - ImageResizer.resizeImage( InBuf, 640, 480, 0, OutBuf, 1024, 768, 3, 0 ); - (multi-threaded operation requires additional coding, see the documentation) - -For low-ringing performance: - - avir :: CImageResizer<> ImageResizer( 8, 0, avir :: CImageResizerParamsLR() ); - -To use the built-in gamma correction, an object of the -`avir::CImageResizerVars` class with its variable `UseSRGBGamma` set to "true" -should be supplied to the `resizeImage()` function. Note that the gamma -correction is applied to all channels (e.g. alpha-channel) in the current -implementation. - - avir :: CImageResizerVars Vars; - Vars.UseSRGBGamma = true; - -Dithering (error-diffusion dither which is perceptually good) can be enabled -this way: - - typedef avir :: fpclass_def< float, float, - avir :: CImageResizerDithererErrdINL< float > > fpclass_dith; - avir :: CImageResizer< fpclass_dith > ImageResizer( 8 ); - -The library is able to process images of any bit depth: this includes 8-bit, -16-bit, float and double types. Larger integer and signed integer types are -not supported. Supported source and destination image sizes are only limited -by the available system memory. - -The code of this library was commented in the [Doxygen](http://www.doxygen.org/) -style. To generate the documentation locally you may run the -`doxygen ./other/avirdoxy.txt` command from the library's directory. Note that -the code was suitably documented allowing you to make modifications, and to -gain full understanding of the algorithm. - -Preliminary tests show that this library (compiled with Intel C++ Compiler -18.2 with AVX2 instructions enabled, without explicit SIMD resizing code) can -resize 8-bit RGB 5184x3456 (17.9 Mpixel) 3-channel image down to 1920x1280 -(2.5 Mpixel) image in 245 milliseconds, utilizing a single thread, on Intel -Core i7-7700K processor-based system without overclocking. This scales down to -74 milliseconds if 8 threads are utilized. - -Multi-threaded operation is not provided by this library "out of the box". -The multi-threaded (horizontally-threaded) infrastructure is available, but -requires additional system-specific interfacing code for engagement. - -## SIMD Usage Information ## -This library is capable of using SIMD floating point types for internal -variables. This means that up to 4 color channels can be processed in -parallel. Since the default interleaved processing algorithm itself remains -non-SIMD, the use of SIMD internal types is not practical for 1- and 2-channel -image resizing (due to overhead). SIMD internal type can be used this way: - - #include "avir_float4_sse.h" - avir :: CImageResizer< avir :: fpclass_float4 > ImageResizer( 8 ); - -For 1-channel and 2-channel image resizing when AVX instructions are allowed -it may be reasonable to utilize de-interleaved SIMD processing algorithm. -While it gives no performance benefit if the "float4" SSE processing type is -used, it offers some performance boost if the "float8" AVX processing type is -used (given dithering is not performed, or otherwise performance is reduced at -the dithering stage since recursive dithering cannot be parallelized). The -internal type remains non-SIMD "float". De-interleaved algorithm can be used -this way: - - #include "avir_float8_avx.h" - avir :: CImageResizer< avir :: fpclass_float8_dil > ImageResizer( 8 ); - -It's important to note that on the latest Intel processors (i7-7700K and -probably later) the use of the aforementioned SIMD-specific resizing code may -not be justifiable, or may be even counter-productive due to many factors: -memory bandwidth bottleneck, increased efficiency of processor's circuitry -utilization and out-of-order execution, automatic SIMD optimizations performed -by the compiler. This is at least true when compiling 64-bit code with Intel -C++ Compiler 18.2 with /QxSSE4.2, or especially with the /QxCORE-AVX2 option. -SSE-specific resizing code may still be a little bit more efficient for -4-channel image resizing. - -## Notes ## -This library was tested for compatibility with [GNU C++](http://gcc.gnu.org/), -[Microsoft Visual C++](http://www.microsoft.com/visualstudio/eng/products/visual-studio-express-products) -and [Intel C++](http://software.intel.com/en-us/c-compilers) compilers, on 32- -and 64-bit Windows, macOS and CentOS Linux. The code was also tested with -Dr.Memory/Win32 for the absence of uninitialized or unaddressable memory -accesses. - -All code is fully "inline", without the need to compile any source files. The -memory footprint of the library itself is very modest, except that the size of -the temporary image buffers depends on the input and output image sizes, and -is proportionally large. - -The "heart" of resizing algorithm's quality resides in the parameters defined -via the `avir::CImageResizerParams` structure. While the default set of -parameters that offers a good quality was already provided, there is -(probably) still a place for improvement exists, and the default parameters -may change in a future update. If you need to recall an exact set of -parameters, simply save them locally for a later use. - -When the algorithm is run with no resizing applied (k=1), the result of -resizing will not be an exact, but a very close copy of the source image. The -reason for such inexactness is that the image is always low-pass filtered at -first to reduce aliasing during subsequent resizing, and at last filtered by a -correction filter. Such approach allows algorithm to maintain a stable level -of quality regardless of the resizing "k" factor used. - -This library includes a binary command line tool "imageresize" for major -desktop platforms. This tool was designed to be used as a demonstration of -library's performance, and as a reference, it is multi-threaded (the `-t` -switch can be used to control the number of threads utilized). This tool uses -plain "float" processing (no explicit SIMD) and relies on automatic compiler -optimization (with Win64 binary being the "main" binary as it was compiled -with the best ICC optimization options for the time being). This tool uses the -following libraries: -* turbojpeg Copyright (c) 2009-2013 D. R. Commander -* libpng Copyright (c) 1998-2013 Glenn Randers-Pehrson -* zlib Copyright (c) 1995-2013 Jean-loup Gailly and Mark Adler - -Note that you can enable gamma-correction with the `-g` switch. However, -sometimes gamma-correction produces "greenish/reddish/bluish haze" since -low-amplitude oscillations produced by resizing at object boundaries are -amplified by gamma correction. This can also have an effect of reduced -contrast. - -## Interpolation Discussion ## -The use of certain low-pass filters and 2X upsampling in this library is -hardly debatable, because they are needed to attain a certain anti-aliasing -effect and keep ringing artifacts low. But the use of sinc function-based -interpolation filter that is 18 taps-long (may be higher, up to 36 taps in -practice) can be questioned, because even in 0th order case such -interpolation filter requires 18 multiply-add operations. Comparatively, an -optimal Hermite or cubic interpolation spline requires 8 multiply and 11 add -operations. - -One of the reasons 18-tap filter is preferred, is because due to memory -bandwidth limitations using a lower-order filter does not provide any -significant performance increase (e.g. 14-tap filter is less than 5% more -efficient overall). At the same time, in comparison to cubic spline, 18-tap -filter embeds a low-pass filter that rejects signal above 0.5\*pi (provides -additional anti-aliasing filtering), and this filter has a consistent shape at -all fractional offsets. Splines have a varying low-pass filter shape at -different fractional offsets (e.g. no low-pass filtering at 0.0 offset, -and maximal low-pass filtering at 0.5 offset). 18-tap filter also offers a -superior stop-band attenuation which almost guarantees absence of artifacts if -the image is considerably sharpened afterwards. - -## Why 2X upsizing in AVIR? ## -Classic approaches to image resizing do not perform an additional 2X upsizing. -So, why such upsizing is needed at all in AVIR? Indeed, image resizing can be -implemented using a single interpolation filter which is applied to the source -image directly. However, such approach has limitations: - -First of all, speaking about non-2X-upsized resizing, during upsizing the -interpolation filter has to be tuned to a frequency close to pi (Nyquist) in -order to reduce high-frequency smoothing: this reduces the space left for -filter optimization. Beside that, during downsizing, a filter that performs -well and predictable when tuned to frequencies close to the Nyquist frequency, -may become distorted in its spectral shape when it is tuned to lower -frequencies. That is why it is usually a good idea to have filter's stop-band -begin below Nyquist so that the transition band's shape remains stable at any -lower-frequency setting. At the same time, this requirement complicates a -further corrective filtering, because correction filter may become too steep -at the point where the stop-band begins. - -Secondly, speaking about non-2X-upsized resizing, filter has to be very short -(with a base length of 5-7 taps, further multiplied by the resizing factor) or -otherwise the ringing artifacts will be very strong: it is a general rule that -the steeper the filter is around signal frequencies being removed the higher -the ringing artifacts are. That is why it is preferred to move steep -transitions into the spectral area with a quieter signal. A short filter also -means it cannot provide a strong "beyond-Nyquist" stop-band attenuation, so an -interpolated image will look a bit edgy or not very clean due to stop-band -artifacts. - -To sum up, only additional controlled 2X upsizing provides enough spectral -space to design interpolation filter without visible ringing artifacts yet -providing a strong stop-band attenuation and stable spectral characteristics -(good at any resizing "k" factor). Moreover, 2X upsizing becomes very -important in maintaining a good resizing quality when downsizing and upsizing -by small "k" factors, in the range 0.5 to 2: resizing approaches that do not -perform 2X upsizing usually cannot design a good interpolation filter for such -factors just because there is not enough spectral space available. - -## Why Peaked Cosine in AVIR? ## -First of all, AVIR is a general solution to image resizing problem. That is -why it should not be directly compared to "spline interpolation" or "Lanczos -resampling", because the latter two are only means to design interpolation -filters, and they can be implemented in a variety of ways, even in sub-optimal -ways. Secondly, with only a minimal effort AVIR can be changed to use any -existing interpolation formula and any window function, but this is just not -needed. - -An effort was made to compare Peaked Cosine to Lanczos window function, and -here is the author's opinion. Peaked Cosine has two degrees of freedom whereas -Lanczos has one degree of freedom. While both functions can be used with -acceptable results, Peaked Cosine window function used in automatic parameter -optimization really pushes the limits of frequency response linearity, -anti-aliasing strength (stop-band attenuation) and low-ringing performance -which Lanczos cannot usually achieve. This is true at least when using a -general-purpose downhill simplex optimization method. Lanczos window has good -(but not better) characteristics in several special cases (certain "k" -factors) which makes it of limited use in a general solution such as AVIR. - -Among other window functions (Kaiser, Gaussian, Cauchy, Poisson, generalized -cosine windows) there are no better candidates as well. It looks like Peaked -Cosine function's scalability (it retains stable, almost continously-variable -spectral characteristics at any window parameter values), and its ability to -create "desirable" pass-band ripple in the frequency response near the cutoff -point contribute to its better overall quality. Somehow Peaked Cosine window -function optimization manages to converge to reasonable states in most cases -(that is why AVIR library comes with a set of equally robust, but distinctive -parameter sets) whereas all other window functions tend to produce -unpredictable optimization results. - -The only disadvantage of Peaked Cosine window function is that usable filters -windowed by this function tend to be longer than "usual" (with Kaiser window -being the "golden standard" for filter length per decibel of stop-band -attenuation). This is a price that should be paid for stable spectral -characteristics. - -## Change log ## -Version 2.2: - -* Released AVIR under a permissive MIT license agreement. - -Version 2.1: - -* Fixed error-diffusion dither problems introduced in the previous version. -* Added the `-1` switch to the `imageresize` to enable 1-bit output for -dither's quality evaluation (use together with the `-d` switch). -* Added the `--algparams=` switch to the `imageresize` to control resizing -quality (replaces the `--low-ring` switch). -* Added `avir :: CImageResizerParamsULR` parameter set for lowest-ringing -performance possible (not considerably different to -`avir :: CImageResizerParamsLR`, but a bit lower ringing). - -Version 2.0: - -* Minor inner loop optimizations. -* Lifted the supported image size constraint by switching buffer addressing to -`size_t` from `int`, now image size is limited by the available system memory. -* Added several useful switches to the `imageresize` utility. -* Now `imageresize` does not apply gamma-correction by default. -* Fixed scaling of bit depth-reduction operation. -* Improved error-diffusion dither's signal-to-noise ratio. -* Compiled binaries with AVX2 instruction set (SSE4 for macOS). - -## Users ## -This library is used by: - - * [Contaware.com](http://www.contaware.com/) - -Please drop me a note at aleksey.vaneev@gmail.com and I will include a link to -your software product to the list of users. This list is important at -maintaining confidence in this library among the interested parties. diff --git a/Modules/gin/3rdparty/avir/avir.h b/Modules/gin/3rdparty/avir/avir.h deleted file mode 100755 index 500946b..0000000 --- a/Modules/gin/3rdparty/avir/avir.h +++ /dev/null @@ -1,6198 +0,0 @@ -//$ nobt -//$ nocpp - -/** - * @file avir.h - * - * @brief The "main" inclusion file with all required classes and functions. - * - * This is the "main" inclusion file for the "AVIR" image resizer. This - * inclusion file contains implementation of the AVIR image resizing algorithm - * in its entirety. Also includes several classes and functions that can be - * useful elsewhere. - * - * AVIR Copyright (c) 2015-2019 Aleksey Vaneev - * - * @mainpage - * - * @section intro_sec Introduction - * - * Description is available at https://github.com/avaneev/avir - * - * AVIR is devoted to women. Your digital photos can look good at any size! - * - * @section license License - * - * AVIR License Agreement - * - * The MIT License (MIT) - * - * Copyright (c) 2015-2019 Aleksey Vaneev - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Please credit the author of this library in your documentation in the - * following way: "AVIR image resizing algorithm designed by Aleksey Vaneev" - * - * @version 2.4 - */ - -#ifndef AVIR_CIMAGERESIZER_INCLUDED -#define AVIR_CIMAGERESIZER_INCLUDED - -#include -#include -#include -#include - -namespace avir { - -/** - * The macro defines AVIR version string. - */ - -#define AVIR_VERSION "2.4" - -/** - * The macro equals to "pi" constant, fills 53-bit floating point mantissa. - * Undefined at the end of file. - */ - -#define AVIR_PI 3.1415926535897932 - -/** - * The macro equals to "pi divided by 2" constant, fills 53-bit floating - * point mantissa. Undefined at the end of file. - */ - -#define AVIR_PId2 1.5707963267948966 - -/** - * Rounding function, based on the (int) typecast. Biased result. Not suitable - * for numbers >= 2^31. - * - * @param d Value to round. - * @return Rounded value. Some bias may be introduced. - */ - -template< class T > -inline T round( const T d ) -{ - return( d < 0.0 ? -(T) (int) ( (T) 0.5 - d ) : (T) (int) ( d + (T) 0.5 )); -} - -/** - * Template function "clamps" (clips) the specified value so that it is not - * lesser than "minv", and not greater than "maxv". - * - * @param Value Value to clamp. - * @param minv Minimal allowed value. - * @param maxv Maximal allowed value. - * @return The clamped value. - */ - -template< class T > -inline T clamp( const T& Value, const T minv, const T maxv ) -{ - if( Value < minv ) - { - return( minv ); - } - else - if( Value > maxv ) - { - return( maxv ); - } - else - { - return( Value ); - } -} - -/** - * Power 2.4 approximation function, designed for sRGB gamma correction. - * - * @param x Argument, in the range 0.09 to 1. - * @return Value raised into power 2.4, approximate. - */ - -template< class T > -inline T pow24_sRGB( const T x ) -{ - const double x2 = x * x; - const double x3 = x2 * x; - const double x4 = x2 * x2; - - return( (T) ( 0.0985766365536824 + 0.839474952656502 * x2 + - 0.363287814061725 * x3 - 0.0125559718896615 / - ( 0.12758338921578 + 0.290283465468235 * x ) - - 0.231757513261358 * x - 0.0395365717969074 * x4 )); -} - -/** - * Power 1/2.4 approximation function, designed for sRGB gamma correction. - * - * @param x Argument, in the range 0.003 to 1. - * @return Value raised into power 1/2.4, approximate. - */ - -template< class T > -inline T pow24i_sRGB( const T x ) -{ - const double sx = sqrt( x ); - const double ssx = sqrt( sx ); - const double sssx = sqrt( ssx ); - - return( (T) ( 0.000213364515060263 + 0.0149409239419218 * x + - 0.433973412731747 * sx + ssx * ( 0.659628181609715 * sssx - - 0.0380957908841466 - 0.0706476137208521 * sx ))); -} - -/** - * Function approximately linearizes the sRGB gamma value. - * - * @param s sRGB gamma value, in the range 0 to 1. - * @return Linearized sRGB gamma value, approximated. - */ - -template< class T > -inline T convertSRGB2Lin( const T s ) -{ - const T a = (T) 0.055; - - if( s <= (T) 0.04045 ) - { - return( s / (T) 12.92 ); - } - - return( pow24_sRGB(( s + a ) / ( (T) 1 + a ))); -} - -/** - * Function approximately de-linearizes the linear gamma value. - * - * @param s Linear gamma value, in the range 0 to 1. - * @return sRGB gamma value, approximated. - */ - -template< class T > -inline T convertLin2SRGB( const T s ) -{ - const T a = (T) 0.055; - - if( s <= (T) 0.0031308 ) - { - return( (T) 12.92 * s ); - } - - return(( (T) 1 + a ) * pow24i_sRGB( s ) - a ); -} - -/** - * Function converts (via typecast) specified array of type T1 values of - * length l into array of type T2 values. If T1 is the same as T2, copy - * operation is performed. When copying data at overlapping address spaces, - * "op" should be lower than "ip". - * - * @param ip Input buffer. - * @param[out] op Output buffer. - * @param l The number of elements to copy. - * @param ip Input buffer pointer increment. - * @param op Output buffer pointer increment. - */ - -template< class T1, class T2 > -inline void copyArray( const T1* ip, T2* op, int l, - const int ipinc = 1, const int opinc = 1 ) -{ - while( l > 0 ) - { - *op = (T2) *ip; - op += opinc; - ip += ipinc; - l--; - } -} - -/** - * Function adds values located in array "ip" to array "op". - * - * @param ip Input buffer. - * @param[out] op Output buffer. - * @param l The number of elements to add. - * @param ip Input buffer pointer increment. - * @param op Output buffer pointer increment. - */ - -template< class T1, class T2 > -inline void addArray( const T1* ip, T2* op, int l, - const int ipinc = 1, const int opinc = 1 ) -{ - while( l > 0 ) - { - *op += *ip; - op += opinc; - ip += ipinc; - l--; - } -} - -/** - * Function that replicates a set of adjacent elements several times in a row. - * This operation is usually used to replicate pixels at the start or end of - * image's scanline. - * - * @param ip Source array. - * @param ipl Source array length (usually 1..4, but can be any number). - * @param[out] op Destination buffer. - * @param l Number of times the source array should be replicated (the - * destination buffer should be able to hold ipl * l number of elements). - * @param opinc Destination buffer position increment after replicating the - * source array. This value should be equal to at least ipl. - */ - -template< class T1, class T2 > -inline void replicateArray( const T1* const ip, const int ipl, T2* op, int l, - const int opinc ) -{ - if( ipl == 1 ) - { - while( l > 0 ) - { - op[ 0 ] = ip[ 0 ]; - op += opinc; - l--; - } - } - else - if( ipl == 4 ) - { - while( l > 0 ) - { - op[ 0 ] = ip[ 0 ]; - op[ 1 ] = ip[ 1 ]; - op[ 2 ] = ip[ 2 ]; - op[ 3 ] = ip[ 3 ]; - op += opinc; - l--; - } - } - else - if( ipl == 3 ) - { - while( l > 0 ) - { - op[ 0 ] = ip[ 0 ]; - op[ 1 ] = ip[ 1 ]; - op[ 2 ] = ip[ 2 ]; - op += opinc; - l--; - } - } - else - if( ipl == 2 ) - { - while( l > 0 ) - { - op[ 0 ] = ip[ 0 ]; - op[ 1 ] = ip[ 1 ]; - op += opinc; - l--; - } - } - else - { - while( l > 0 ) - { - int i; - - for( i = 0; i < ipl; i++ ) - { - op[ i ] = ip[ i ]; - } - - op += opinc; - l--; - } - } -} - -/** - * Function calculates frequency response of the specified FIR filter at the - * specified circular frequency. Phase can be calculated as atan2( im, re ). - * Function uses computationally-efficient oscillators instead of "cos" and - * "sin" functions. - * - * @param flt FIR filter's coefficients. - * @param fltlen Number of coefficients (taps) in the filter. - * @param th Circular frequency [0; pi]. - * @param[out] re0 Resulting real part of the complex frequency response. - * @param[out] im0 Resulting imaginary part of the complex frequency response. - * @param fltlat Filter's latency in samples (taps). - */ - -template< class T > -inline void calcFIRFilterResponse( const T* flt, int fltlen, - const double th, double& re0, double& im0, const int fltlat = 0 ) -{ - const double sincr = 2.0 * cos( th ); - double cvalue1; - double svalue1; - - if( fltlat == 0 ) - { - cvalue1 = 1.0; - svalue1 = 0.0; - } - else - { - cvalue1 = cos( -fltlat * th ); - svalue1 = sin( -fltlat * th ); - } - - double cvalue2 = cos( -( fltlat + 1 ) * th ); - double svalue2 = sin( -( fltlat + 1 ) * th ); - - double re = 0.0; - double im = 0.0; - - while( fltlen > 0 ) - { - re += cvalue1 * flt[ 0 ]; - im += svalue1 * flt[ 0 ]; - flt++; - fltlen--; - - double tmp = cvalue1; - cvalue1 = sincr * cvalue1 - cvalue2; - cvalue2 = tmp; - - tmp = svalue1; - svalue1 = sincr * svalue1 - svalue2; - svalue2 = tmp; - } - - re0 = re; - im0 = im; -} - -/** - * Function normalizes FIR filter so that its frequency response at DC is - * equal to DCGain. - * - * @param[in,out] p Filter coefficients. - * @param l Filter length. - * @param DCGain Filter's gain at DC. - * @param pstep "p" array step. - */ - -template< class T > -inline void normalizeFIRFilter( T* const p, const int l, const double DCGain, - const int pstep = 1 ) -{ - double s = 0.0; - T* pp = p; - int i = l; - - while( i > 0 ) - { - s += *pp; - pp += pstep; - i--; - } - - s = DCGain / s; - pp = p; - i = l; - - while( i > 0 ) - { - *pp = (T) ( *pp * s ); - pp += pstep; - i--; - } -} - -/** - * @brief Memory buffer class for element array storage, with capacity - * tracking. - * - * Allows easier handling of memory blocks allocation and automatic - * deallocation for arrays (buffers) consisting of elements of specified - * class. Tracks buffer's capacity in "int" variable; unsuitable for - * allocation of very large memory blocks (with more than 2 billion elements). - * - * This class manages memory space only - it does not perform element class - * construction (initialization) operations. Buffer's required memory address - * alignment specification is supported. - * - * Uses standard library to allocate and deallocate memory. - * - * @tparam T Buffer element's type. - * @tparam capint Buffer capacity's type to use. Use size_t for large buffers. - */ - -template< class T, typename capint = int > -class CBuffer -{ -public: - CBuffer() - : Data( nullptr ) - , DataAligned( nullptr ) - , Capacity( 0 ) - , Alignment( 0 ) - { - } - - /** - * Constructor creates the buffer with the specified capacity. - * - * @param aCapacity Buffer's capacity. - * @param aAlignment Buffer's required memory address alignment. 0 - use - * stdlib's default alignment. - */ - - CBuffer( const capint aCapacity, const int aAlignment = 0 ) - { - allocinit( aCapacity, aAlignment ); - } - - CBuffer( const CBuffer& Source ) - { - allocinit( Source.Capacity, Source.Alignment ); - memcpy( DataAligned, Source.DataAligned, Capacity * sizeof( T )); - } - - ~CBuffer() - { - freeData(); - } - - CBuffer& operator = ( const CBuffer& Source ) - { - alloc( Source.Capacity, Source.Alignment ); - memcpy( DataAligned, Source.DataAligned, Capacity * sizeof( T )); - return( *this ); - } - - /** - * Function allocates memory so that the specified number of elements - * can be stored in *this buffer object. - * - * @param aCapacity Storage for this number of elements to allocate. - * @param aAlignment Buffer's required memory address alignment, - * power-of-2 values only. 0 - use stdlib's default alignment. - */ - - void alloc( const capint aCapacity, const int aAlignment = 0 ) - { - freeData(); - allocinit( aCapacity, aAlignment ); - } - - /** - * Function deallocates any previously allocated buffer. - */ - - void free() - { - freeData(); - Data = nullptr; - DataAligned = nullptr; - Capacity = 0; - Alignment = 0; - } - - /** - * @return The capacity of the element buffer. - */ - - capint getCapacity() const - { - return( Capacity ); - } - - /** - * Function "forces" *this buffer to have an arbitary capacity. Calling - * this function invalidates all further operations except deleting *this - * object. This function should not be usually used at all. Function can - * be used to "model" certain buffer capacity without calling a costly - * memory allocation function. - * - * @param NewCapacity A new "forced" capacity. - */ - - void forceCapacity( const capint NewCapacity ) - { - Capacity = NewCapacity; - } - - /** - * Function reallocates *this buffer to a larger size so that it will be - * able to hold the specified number of elements. Downsizing is not - * performed. Alignment is not changed. - * - * @param NewCapacity New (increased) capacity. - * @param DoDataCopy "True" if data in the buffer should be retained. - */ - - void increaseCapacity( const capint NewCapacity, - const bool DoDataCopy = true ) - { - if( NewCapacity < Capacity ) - { - return; - } - - if( DoDataCopy ) - { - const capint PrevCapacity = Capacity; - T* const PrevData = Data; - T* const PrevDataAligned = DataAligned; - - allocinit( NewCapacity, Alignment ); - memcpy( DataAligned, PrevDataAligned, PrevCapacity * sizeof( T )); - - :: free( PrevData ); - } - else - { - :: free( Data ); - allocinit( NewCapacity, Alignment ); - } - } - - /** - * Function "truncates" (reduces) capacity of the buffer without - * reallocating it. Alignment is not changed. - * - * @param NewCapacity New required capacity. - */ - - void truncateCapacity( const capint NewCapacity ) - { - if( NewCapacity >= Capacity ) - { - return; - } - - Capacity = NewCapacity; - } - - /** - * Function increases capacity so that the specified number of - * elements can be stored. This function increases the previous capacity - * value by third the current capacity value until space for the required - * number of elements is available. Alignment is not changed. - * - * @param ReqCapacity Required capacity. - */ - - void updateCapacity( const capint ReqCapacity ) - { - if( ReqCapacity <= Capacity ) - { - return; - } - - capint NewCapacity = Capacity; - - while( NewCapacity < ReqCapacity ) - { - NewCapacity += NewCapacity / 3 + 1; - } - - increaseCapacity( NewCapacity ); - } - - operator T* () const - { - return( DataAligned ); - } - -private: - T* Data; ///< Element buffer pointer. - ///< - T* DataAligned; ///< Memory address-aligned element buffer pointer. - ///< - capint Capacity; ///< Element buffer capacity. - ///< - int Alignment; ///< Memory address alignment in use. 0 - use stdlib's - ///< default alignment. - ///< - - /** - * Internal element buffer allocation function used during object - * construction. - * - * @param aCapacity Storage for this number of elements to allocate. - * @param aAlignment Buffer's required memory address alignment. 0 - use - * stdlib's default alignment. - */ - - void allocinit( const capint aCapacity, const int aAlignment ) - { - if( aAlignment == 0 ) - { - Data = (T*) :: malloc( aCapacity * sizeof( T )); - DataAligned = Data; - Alignment = 0; - } - else - { - Data = (T*) :: malloc( aCapacity * sizeof( T ) + aAlignment ); - DataAligned = alignptr( Data, aAlignment ); - Alignment = aAlignment; - } - - Capacity = aCapacity; - } - - /** - * Function frees a previously allocated Data buffer. - */ - - void freeData() - { - :: free( Data ); - } - - /** - * Function modifies the specified pointer so that it becomes memory - * address-aligned. - * - * @param ptr Pointer to align. - * @param align Alignment in bytes to apply. - * @return Pointer aligned to align bytes. Works with power-of-2 - * alignments only. If no alignment is necessary, "align" bytes will be - * added to the pointer value. - */ - - template< class Tp > - inline Tp alignptr( const Tp ptr, const uintptr_t align ) - { - return( (Tp) ( (uintptr_t) ptr + align - - ( (uintptr_t) ptr & ( align - 1 ))) ); - } -}; - -/** - * Function optimizes the length of the symmetric-odd FIR filter by removing - * left- and rightmost elements that are below specific threshold. - * - * Synthetic test shows that filter gets optimized in 2..3% of cases and in - * each such case optimization reduces filter length by 6..8%. Optimization, - * however, may skew the results of algorithm modeling and complexity - * calculation leading to a choice of a less optimal algorithm. - * - * @param[in,out] Flt Buffer that contains filter being optimized. - * @param[in,out] FltLatency Variable that holds the current latency of the - * filter. May be adjusted on function return. - * @param Threshold Threshold level. - */ - -template< class T > -inline void optimizeFIRFilter( CBuffer< T >& Flt, int& FltLatency, - T const Threshold = (T) 0.00001 ) -{ - int i; - - // Optimize length. - - for( i = 0; i <= FltLatency; i++ ) - { - if( fabs( Flt[ i ]) >= Threshold || i == FltLatency ) - { - if( i > 0 ) - { - const int NewCapacity = Flt.getCapacity() - i * 2; - copyArray( &Flt[ i ], &Flt[ 0 ], NewCapacity ); - Flt.truncateCapacity( NewCapacity ); - FltLatency -= i; - } - - break; - } - } -} - -/** - * @brief Array of structured objects. - * - * Implements allocation of a linear array of objects of class T (which are - * initialized), addressable via operator[]. Each object is created via the - * "operator new". New object insertions are quick since implementation uses - * prior space allocation (capacity), thus not requiring frequent memory block - * reallocations. - * - * @tparam T Array element's type. - */ - -template< class T > -class CStructArray -{ -public: - CStructArray() - : ItemCount( 0 ) - { - } - - CStructArray( const CStructArray& Source ) - : ItemCount( 0 ) - , Items( Source.getItemCount() ) - { - while( ItemCount < Source.getItemCount() ) - { - Items[ ItemCount ] = new T( Source[ ItemCount ]); - ItemCount++; - } - } - - ~CStructArray() - { - clear(); - } - - CStructArray& operator = ( const CStructArray& Source ) - { - clear(); - - const int NewCount = Source.ItemCount; - Items.updateCapacity( NewCount ); - - while( ItemCount < NewCount ) - { - Items[ ItemCount ] = new T( Source[ ItemCount ]); - ItemCount++; - } - - return( *this ); - } - - T& operator []( const int Index ) - { - return( *Items[ Index ]); - } - - const T& operator []( const int Index ) const - { - return( *Items[ Index ]); - } - - /** - * Function creates a new object of type T with the default constructor - * and adds this object to the array. - * - * @return Reference to a newly added object. - */ - - T& add() - { - if( ItemCount == Items.getCapacity() ) - { - Items.increaseCapacity( ItemCount * 3 / 2 + 1 ); - } - - Items[ ItemCount ] = new T(); - ItemCount++; - - return( (*this)[ ItemCount - 1 ]); - } - - /** - * Function changes number of allocated items. New items are created with - * the default constructor. If NewCount is below the current item count, - * items that are above NewCount range will be destructed. - * - * @param NewCount New requested item count. - */ - - void setItemCount( const int NewCount ) - { - if( NewCount > ItemCount ) - { - Items.increaseCapacity( NewCount ); - - while( ItemCount < NewCount ) - { - Items[ ItemCount ] = new T(); - ItemCount++; - } - } - else - { - while( ItemCount > NewCount ) - { - ItemCount--; - delete Items[ ItemCount ]; - } - } - } - - /** - * Function erases all items of *this array. - */ - - void clear() - { - while( ItemCount > 0 ) - { - ItemCount--; - delete Items[ ItemCount ]; - } - } - - /** - * @return The number of allocated items. - */ - - int getItemCount() const - { - return( ItemCount ); - } - -private: - int ItemCount; ///< The number of items available in the array. - ///< - CBuffer< T* > Items; ///< Element buffer. - ///< -}; - -/** - * @brief Sine signal generator class. - * - * Class implements sine signal generator without biasing, with - * constructor-based initalization only. This generator uses oscillator - * instead of "sin" function. - */ - -class CSineGen -{ -public: - /** - * Constructor initializes *this sine signal generator. - * - * @param si Sine function increment, in radians. - * @param ph Starting phase, in radians. Add 0.5 * AVIR_PI for cosine - * function. - */ - - CSineGen( const double si, const double ph ) - : svalue1( sin( ph )) - , svalue2( sin( ph - si )) - , sincr( 2.0 * cos( si )) - { - } - - /** - * @return The next value of the sine function, without biasing. - */ - - double generate() - { - const double res = svalue1; - - svalue1 = sincr * res - svalue2; - svalue2 = res; - - return( res ); - } - -private: - double svalue1; ///< Current sine value. - ///< - double svalue2; ///< Previous sine value. - ///< - double sincr; ///< Sine value increment. - ///< -}; - -/** - * @brief Peaked Cosine window function generator class. - * - * Class implements Peaked Cosine window function generator. Generates the - * right-handed half of the window function. The Alpha parameter of this - * window function offers the control of the balance between the early and - * later taps of the filter. E.g. at Alpha=1 both early and later taps are - * attenuated, but at Alpha=4 mostly later taps are attenuated. This offers a - * great control over ringing artifacts produced by a low-pass filter in image - * processing, without compromising achieved image sharpness. - */ - -class CDSPWindowGenPeakedCosine -{ -public: - /** - * Constructor initializes *this window function generator. - * - * @param aAlpha Alpha parameter, affects the peak shape (peak - * augmentation) of the window function. Should be >= 1.0. - * @param aLen2 Half filter's length (non-truncated). - */ - - CDSPWindowGenPeakedCosine( const double aAlpha, const double aLen2 ) - : Alpha( aAlpha ) - , Len2( aLen2 ) - , wn( 0 ) - , w1( AVIR_PId2 / Len2, AVIR_PI * 0.5 ) - { - } - - /** - * @return The next Peaked Cosine window function coefficient. - */ - - double generate() - { - const double h = pow( wn / Len2, Alpha ); - wn++; - - return( w1.generate() * ( 1.0 - h )); - } - -private: - double Alpha; ///< Alpha parameter, affects the peak shape of window. - ///< - double Len2; ///< Half length of the window function. - ///< - int wn; ///< Window function integer position. 0 - center of the - ///< window function. - ///< - CSineGen w1; ///< Sine-wave generator. - ///< -}; - -/** - * @brief FIR filter-based equalizer generator. - * - * Class implements an object used to generate symmetric-odd FIR filters with - * the specified frequency response (aka paragraphic equalizer). The - * calculated filter is windowed by the Peaked Cosine window function. - * - * In image processing, due to short length of filters being used (6-8 taps) - * the resulting frequency response of the filter is approximate and may be - * mathematically imperfect, but still adequate to the visual requirements. - * - * On a side note, this equalizer generator can be successfully used for audio - * signal equalization as well: for example, it is used in almost the same - * form in Voxengo Marvel GEQ equalizer plug-in. - * - * Filter generation is based on decomposition of frequency range into - * spectral bands, with each band represented by linear and ramp "kernels". - * When the filter is built, these kernels are combined together with - * different weights that approximate the required frequency response. - */ - -class CDSPFIREQ -{ -public: - /** - * Function initializes *this object with the required parameters. The - * gain of frequencies beyond the MinFreq..MaxFreq range are controlled by - * the first and the last band's gain. - * - * @param SampleRate Processing sample rate (use 2 for image processing). - * @param aFilterLength Required filter length in samples (taps). The - * actual filter length is truncated to an integer value. - * @param aBandCount Number of band crossover points required to control, - * including bands at MinFreq and MaxFreq. - * @param MinFreq Minimal frequency that should be controlled. - * @param MaxFreq Maximal frequency that should be controlled. - * @param IsLogBands "True" if the bands should be spaced logarithmically. - * @param WFAlpha Peaked Cosine window function's Alpha parameter. - */ - - void init( const double SampleRate, const double aFilterLength, - const int aBandCount, const double MinFreq, const double MaxFreq, - const bool IsLogBands, const double WFAlpha ) - { - FilterLength = aFilterLength; - BandCount = aBandCount; - - CenterFreqs.alloc( BandCount ); - - z = (int) ceil( FilterLength * 0.5 ); - zi = z + ( z & 1 ); - z2 = z * 2; - - CBuffer< double > oscbuf( z2 ); - initOscBuf( oscbuf ); - - CBuffer< double > winbuf( z ); - initWinBuf( winbuf, WFAlpha ); - - UseFirstVirtBand = ( MinFreq > 0.0 ); - const int k = zi * ( BandCount + ( UseFirstVirtBand ? 1 : 0 )); - Kernels1.alloc( k ); - Kernels2.alloc( k ); - - double m; // Frequency step multiplier. - double mo; // Frequency step offset (addition). - - if( IsLogBands ) - { - m = exp( log( MaxFreq / MinFreq ) / ( BandCount - 1 )); - mo = 0.0; - } - else - { - m = 1.0; - mo = ( MaxFreq - MinFreq ) / ( BandCount - 1 ); - } - - double f = MinFreq; - double x1 = 0.0; - double x2; - int si; - - if( UseFirstVirtBand ) - { - si = 0; - } - else - { - si = 1; - CenterFreqs[ 0 ] = 0.0; - f = f * m + mo; - } - - double* kernbuf1 = &Kernels1[ 0 ]; - double* kernbuf2 = &Kernels2[ 0 ]; - int i; - - for( i = si; i < BandCount; i++ ) - { - x2 = f * 2.0 / SampleRate; - CenterFreqs[ i ] = x2; - - fillBandKernel( x1, x2, kernbuf1, kernbuf2, oscbuf, winbuf ); - - kernbuf1 += zi; - kernbuf2 += zi; - x1 = x2; - f = f * m + mo; - } - - if( x1 < 1.0 ) - { - UseLastVirtBand = true; - fillBandKernel( x1, 1.0, kernbuf1, kernbuf2, oscbuf, winbuf ); - } - else - { - UseLastVirtBand = false; - } - } - - /** - * @return Filter's length, in samples (taps). - */ - - int getFilterLength() const - { - return( z2 - 1 ); - } - - /** - * @return Filter's latency (group delay), in samples (taps). - */ - - int getFilterLatency() const - { - return( z - 1 ); - } - - /** - * Function creates symmetric-odd FIR filter with the specified gain - * levels at band crossover points. - * - * @param BandGains Array of linear gain levels, count=BandCount specified - * in the init() function. - * @param[out] Filter Output filter buffer, length = getFilterLength(). - */ - - void buildFilter( const double* const BandGains, double* const Filter ) - { - const double* kernbuf1 = &Kernels1[ 0 ]; - const double* kernbuf2 = &Kernels2[ 0 ]; - double x1 = 0.0; - double y1 = BandGains[ 0 ]; - double x2; - double y2; - - int i; - int si; - - if( UseFirstVirtBand ) - { - si = 1; - x2 = CenterFreqs[ 0 ]; - y2 = y1; - } - else - { - si = 2; - x2 = CenterFreqs[ 1 ]; - y2 = BandGains[ 1 ]; - } - - copyBandKernel( Filter, kernbuf1, kernbuf2, y1 - y2, - x1 * y2 - x2 * y1 ); - - kernbuf1 += zi; - kernbuf2 += zi; - x1 = x2; - y1 = y2; - - for( i = si; i < BandCount; i++ ) - { - x2 = CenterFreqs[ i ]; - y2 = BandGains[ i ]; - - addBandKernel( Filter, kernbuf1, kernbuf2, y1 - y2, - x1 * y2 - x2 * y1 ); - - kernbuf1 += zi; - kernbuf2 += zi; - x1 = x2; - y1 = y2; - } - - if( UseLastVirtBand ) - { - addBandKernel( Filter, kernbuf1, kernbuf2, y1 - y2, - x1 * y2 - y1 ); - } - - for( i = 0; i < z - 1; i++ ) - { - Filter[ z + i ] = Filter[ z - 2 - i ]; - } - } - - /** - * Function calculates filter's length (in samples) and latency depending - * on the required non-truncated filter length. - * - * @param aFilterLength Required filter length in samples (non-truncated). - * @param[out] Latency Resulting latency (group delay) of the filter, - * in samples (taps). - * @return Filter length in samples (taps). - */ - - static int calcFilterLength( const double aFilterLength, int& Latency ) - { - const int l = (int) ceil( aFilterLength * 0.5 ); - Latency = l - 1; - - return( l * 2 - 1 ); - } - -private: - double FilterLength; ///< Length of filter. - ///< - int z; ///< Equals (int) ceil( FilterLength * 0.5 ). - ///< - int zi; ///< Equals "z" if z is even, or z + 1 if z is odd. Used as a - ///< Kernels1 and Kernels2 size multiplier and kernel buffer increment - ///< to make sure each kernel buffer is 16-byte aligned. - ///< - int z2; ///< Equals z * 2. - ///< - int BandCount; ///< Number of controllable bands. - ///< - CBuffer< double > CenterFreqs; ///< Center frequencies for all bands, - ///< normalized to 0.0-1.0 range. - ///< - CBuffer< double > Kernels1; ///< Half-length kernel buffers for each - ///< spectral band (linear part). - ///< - CBuffer< double > Kernels2; ///< Half-length kernel buffers for each - ///< spectral band (ramp part). - ///< - bool UseFirstVirtBand; ///< "True" if the first virtual band - ///< (between 0.0 and MinFreq) should be used. The first virtual band - ///< won't be used if MinFreq equals 0.0. - ///< - bool UseLastVirtBand; ///< "True" if the last virtual band (between - ///< MaxFreq and SampleRate * 0.5) should be used. The last virtual - ///< band won't be used if MaxFreq * 2.0 equals SampleRate. - ///< - - /** - * Function initializes the "oscbuf" used in the fillBandKernel() - * function. - * - * @param oscbuf Oscillator buffer, length = z * 2. - */ - - void initOscBuf( double* oscbuf ) const - { - int i = z; - - while( i > 0 ) - { - oscbuf[ 0 ] = 0.0; - oscbuf[ 1 ] = 1.0; - oscbuf += 2; - i--; - } - } - - /** - * Function initializes window function buffer. This function generates - * Peaked Cosine window function. - * - * @param winbuf Windowing buffer. - * @param Alpha Peaked Cosine alpha parameter. - */ - - void initWinBuf( double* winbuf, const double Alpha ) const - { - CDSPWindowGenPeakedCosine wf( Alpha, FilterLength * 0.5 ); - int i; - - for( i = 1; i <= z; i++ ) - { - winbuf[ z - i ] = wf.generate(); - } - } - - /** - * Function fills first half of symmetric-odd FIR kernel for the band. - * This function should be called successively for adjacent bands. - * Previous band's x2 should be equal to current band's x1. A band kernel - * consists of 2 elements: linear kernel and ramp kernel. - * - * @param x1 Band's left corner frequency (0..1). - * @param x2 Band's right corner frequency (0..1). - * @param kernbuf1 Band kernel buffer 1 (linear part), length = z. - * @param kernbuf2 Band kernel buffer 2 (ramp part), length = z. - * @param oscbuf Oscillation buffer. Before the first call of the - * fillBandKernel() should be initialized with the call of the - * initOscBuf() function. - * @param winbuf Buffer that contains windowing function. - */ - - void fillBandKernel( const double x1, const double x2, double* kernbuf1, - double* kernbuf2, double* oscbuf, const double* const winbuf ) - { - const double s2_incr = AVIR_PI * x2; - const double s2_coeff = 2.0 * cos( s2_incr ); - - double s2_value1 = sin( s2_incr * ( -z + 1 )); - double c2_value1 = sin( s2_incr * ( -z + 1 ) + AVIR_PI * 0.5 ); - oscbuf[ 0 ] = sin( s2_incr * -z ); - oscbuf[ 1 ] = sin( s2_incr * -z + AVIR_PI * 0.5 ); - - int ks; - - for( ks = 1; ks < z; ks++ ) - { - const int ks2 = ks * 2; - const double s1_value1 = oscbuf[ ks2 ]; - const double c1_value1 = oscbuf[ ks2 + 1 ]; - oscbuf[ ks2 ] = s2_value1; - oscbuf[ ks2 + 1 ] = c2_value1; - - const double x = AVIR_PI * ( ks - z ); - const double v0 = winbuf[ ks - 1 ] / (( x1 - x2 ) * x ); - - kernbuf1[ ks - 1 ] = ( x2 * s2_value1 - x1 * s1_value1 + - ( c2_value1 - c1_value1 ) / x ) * v0; - - kernbuf2[ ks - 1 ] = ( s2_value1 - s1_value1 ) * v0; - - s2_value1 = s2_coeff * s2_value1 - oscbuf[ ks2 - 2 ]; - c2_value1 = s2_coeff * c2_value1 - oscbuf[ ks2 - 1 ]; - } - - kernbuf1[ z - 1 ] = ( x2 * x2 - x1 * x1 ) / ( x1 - x2 ) * 0.5; - kernbuf2[ z - 1 ] = -1.0; - } - - /** - * Function copies band kernel's elements to the output buffer. - * - * @param outbuf Output buffer. - * @param kernbuf1 Kernel buffer 1 (linear part). - * @param kernbuf2 Kernel buffer 2 (ramp part). - * @param c Multiplier for linear kernel element. - * @param d Multiplier for ramp kernel element. - */ - - void copyBandKernel( double* outbuf, const double* const kernbuf1, - const double* const kernbuf2, const double c, const double d ) const - { - int ks; - - for( ks = 0; ks < z; ks++ ) - { - outbuf[ ks ] = c * kernbuf1[ ks ] + d * kernbuf2[ ks ]; - } - } - - /** - * Function adds band kernel's elements to the output buffer. - * - * @param outbuf Output buffer. - * @param kernbuf1 Kernel buffer 1 (linear part). - * @param kernbuf2 Kernel buffer 2 (ramp part). - * @param c Multiplier for linear kernel element. - * @param d Multiplier for ramp kernel element. - */ - - void addBandKernel( double* outbuf, const double* const kernbuf1, - const double* const kernbuf2, const double c, const double d ) const - { - int ks; - - for( ks = 0; ks < z; ks++ ) - { - outbuf[ ks ] += c * kernbuf1[ ks ] + d * kernbuf2[ ks ]; - } - } -}; - -/** - * @brief Low-pass filter windowed by Peaked Cosine window function. - * - * This class implements calculation of linear-phase symmetric-odd FIR - * low-pass filter windowed by the Peaked Cosine window function, for image - * processing applications. - */ - -class CDSPPeakedCosineLPF -{ -public: - int fl2; ///< Half filter's length, excluding the peak value. This value - ///< can be also used as filter's latency in samples (taps). - ///< - int FilterLen; ///< Filter's length in samples (taps). - ///< - - /** - * Constructor initalizes *this object. - * - * @param aLen2 Half-length (non-truncated) of low-pass filter, in samples - * (taps). - * @param aFreq2 Low-pass filter's corner frequency [0; pi]. - * @param aAlpha Peaked Cosine window function Alpha parameter. - */ - - CDSPPeakedCosineLPF( const double aLen2, const double aFreq2, - const double aAlpha ) - : fl2( (int) ceil( aLen2 ) - 1 ) - , FilterLen( fl2 + fl2 + 1 ) - , Len2( aLen2 ) - , Freq2( aFreq2 ) - , Alpha( aAlpha ) - { - } - - /** - * Function generates a linear-phase low-pass filter windowed by Peaked - * Cosine window function. - * - * @param[out] op Output buffer, length = FilterLen (fl2 * 2 + 1). - * @param DCGain Required gain at DC. The resulting filter will be - * normalized to achieve this DC gain. - */ - - template< class T > - void generateLPF( T* op, const double DCGain ) - { - CDSPWindowGenPeakedCosine wf( Alpha, Len2 ); - CSineGen f2( Freq2, 0.0 ); - - op += fl2; - T* op2 = op; - f2.generate(); - int t = 1; - - *op = (T) ( Freq2 * wf.generate() / AVIR_PI ); - double s = *op; - - while( t <= fl2 ) - { - const double v = f2.generate() * wf.generate() / t / AVIR_PI; - op++; - op2--; - *op = (T) v; - *op2 = (T) v; - s += *op + *op2; - t++; - } - - t = FilterLen; - s = DCGain / s; - - while( t > 0 ) - { - *op2 = (T) ( *op2 * s ); - op2++; - t--; - } - } - -private: - double Len2; ///< Half-length (non-truncated) of low-pass filter, in - ///< samples (taps). - ///< - double Freq2; ///< Low-pass filter's corner frequency. - ///< - double Alpha; ///< Peaked Cosine window function Alpha parameter. - ///< -}; - -/** - * @brief Buffer class for parametrized low-pass filter. - * - * This class extends the CBuffer< double > class by adding several variables - * that define a symmetric-odd FIR low-pass filter windowed by Peaked Cosine - * window function. This class can be used to compare filters without - * comparing their buffer contents. - */ - -class CFltBuffer : public CBuffer< double > -{ -public: - double Len2; ///< Half-length (non-truncated) of low-pass filters, in - ///< samples (taps). - ///< - double Freq; ///< Low-pass filter's corner frequency. - ///< - double Alpha; ///< Peaked Cosine window function Alpha parameter. - ///< - double DCGain; ///< DC gain applied to the filter. - ///< - - CFltBuffer() - : CBuffer< double >() - , Len2( 0.0 ) - , Freq( 0.0 ) - , Alpha( 0.0 ) - , DCGain( 0.0 ) - { - } - - /** - * @param b2 Filter buffer to compare *this object to. - * @return Operator returns "true" if both filters have same parameters. - */ - - bool operator == ( const CFltBuffer& b2 ) const - { - return( Len2 == b2.Len2 && Freq == b2.Freq && Alpha == b2.Alpha && - DCGain == b2.DCGain ); - } -}; - -/** - * @brief Sinc function-based fractional delay filter bank. - * - * Class implements storage and initialization of a bank of sinc - * function-based fractional delay filters, expressed as 1st order polynomial - * interpolation coefficients. The filters are produced from a single "long" - * windowed low-pass filter. Also supports 0th-order ("nearest neighbor") - * interpolation. - * - * This class also supports multiplication of each fractional delay filter by - * an external filter (usually a low-pass filter). - * - * @tparam fptype Specifies storage type of the filter coefficients bank. The - * filters are initially calculated using the "double" precision. - */ - -template< class fptype > -class CDSPFracFilterBankLin -{ -public: - CDSPFracFilterBankLin() - : Order( -1 ) - { - } - - /** - * Copy constructor copies a limited set of parameters of the source - * filter bank. The actual filters are not copied. Such copying is used - * during filtering steps "modeling" stage. A further init() function - * call is required. - * - * @param s Source filter bank. - */ - - void copyInitParams( const CDSPFracFilterBankLin& s ) - { - WFLen2 = s.WFLen2; - WFFreq = s.WFFreq; - WFAlpha = s.WFAlpha; - FracCount = s.FracCount; - Order = s.Order; - Alignment = s.Alignment; - SrcFilterLen = s.SrcFilterLen; - FilterLen = s.FilterLen; - FilterSize = s.FilterSize; - IsSrcTableBuilt = false; - ExtFilter = s.ExtFilter; - TableFillFlags.alloc( s.TableFillFlags.getCapacity() ); - int i; - - // Copy table fill flags, but shifted so that further initialization - // is still possible (such feature should not be used, though). - - for( i = 0; i < TableFillFlags.getCapacity(); i++ ) - { - TableFillFlags[ i ] = (uint8_t) ( s.TableFillFlags[ i ] << 2 ); - } - } - - /** - * Operator compares *this filter bank and another filter bank and returns - * "true" if their parameters are equal. Alignment is not taken into - * account. - * - * @param s Filter bank to compare to. - * @return "True" if compared banks have equal parameters. - */ - - bool operator == ( const CDSPFracFilterBankLin& s ) const - { - return( Order == s.Order && WFLen2 == s.WFLen2 && - WFFreq == s.WFFreq && WFAlpha == s.WFAlpha && - FracCount == s.FracCount && ExtFilter == s.ExtFilter ); - } - - /** - * Function initializes (builds) the filter bank based on the supplied - * parameters. If the supplied parameters are equal to previously defined - * parameters, function does nothing (alignment is assumed to be never - * changing between the init() function calls). - * - * @param ReqFracCount Required number of fractional delays in the filter - * bank. The minimal value is 2. - * @param ReqOrder Required order of the interpolation polynomial - * (0 or 1). - * @param BaseLen Low-pass filter's base length, in samples (taps). - * Affects the actual length of the filter and its overall steepness. - * @param Cutoff Low-pass filter's normalized cutoff frequency [0; 1]. - * @param aWFAlpha Peaked Cosine window function's Alpha parameter. - * @param aExtFilter External filter to apply to each fractional delay - * filter. - * @param aAlignment Memory alignment of the filter bank, power-of-2 - * value. 0 - use default stdlib alignment. - * @param FltLenAlign Filter's length alignment, power-of-2 value. - */ - - void init( const int ReqFracCount, const int ReqOrder, - const double BaseLen, const double Cutoff, const double aWFAlpha, - const CFltBuffer& aExtFilter, const int aAlignment = 0, - const int FltLenAlign = 1 ) - { - double NewWFLen2 = 0.5 * BaseLen * ReqFracCount; - double NewWFFreq = AVIR_PI * Cutoff / ReqFracCount; - double NewWFAlpha = aWFAlpha; - - if( ReqOrder == Order && NewWFLen2 == WFLen2 && NewWFFreq == WFFreq && - NewWFAlpha == WFAlpha && ReqFracCount == FracCount && - aExtFilter == ExtFilter ) - { - IsInitRequired = false; - return; - } - - WFLen2 = NewWFLen2; - WFFreq = NewWFFreq; - WFAlpha = NewWFAlpha; - FracCount = ReqFracCount; - Order = ReqOrder; - Alignment = aAlignment; - ExtFilter = aExtFilter; - - CDSPPeakedCosineLPF p( WFLen2, WFFreq, WFAlpha ); - SrcFilterLen = ( p.fl2 / ReqFracCount + 1 ) * 2; - - const int ElementSize = ReqOrder + 1; - FilterLen = SrcFilterLen; - - if( ExtFilter.getCapacity() > 0 ) - { - FilterLen += ExtFilter.getCapacity() - 1; - } - - FilterLen = ( FilterLen + FltLenAlign - 1 ) & ~( FltLenAlign - 1 ); - FilterSize = FilterLen * ElementSize; - IsSrcTableBuilt = false; - IsInitRequired = true; - } - - /** - * @return The length of each fractional delay filter, in samples (taps). - * Always an even value. - */ - - int getFilterLen() const - { - return( FilterLen ); - } - - /** - * @return The number of fractional filters in use by *this bank. - */ - - int getFracCount() const - { - return( FracCount ); - } - - /** - * @return The order of the interpolation polynomial. - */ - - int getOrder() const - { - return( Order ); - } - - /** - * Function returns the pointer to the specified interpolation table - * filter. - * - * @param i Filter (fractional delay) index, in the range 0 to - * ReqFracCount - 1, inclusive. - * @return Pointer to filter. Higher order polynomial coefficients are - * stored after after previous order coefficients, separated by FilterLen - * elements. - */ - - const fptype* getFilter( const int i ) - { - if( !IsSrcTableBuilt ) - { - buildSrcTable(); - } - - fptype* const Res = &Table[ i * FilterSize ]; - - if(( TableFillFlags[ i ] & 2 ) == 0 ) - { - createFilter( i ); - TableFillFlags[ i ] |= 2; - - if( Order > 0 ) - { - createFilter( i + 1 ); - const fptype* const Res2 = Res + FilterSize; - fptype* const op = Res + FilterLen; - int j; - - // Create higher-order interpolation coefficients (linear - // interpolation). - - for( j = 0; j < FilterLen; j++ ) - { - op[ j ] = Res2[ j ] - Res[ j ]; - } - } - } - - return( Res ); - } - - /** - * Function makes sure all fractional delay filters were created. - */ - - void createAllFilters() - { - int i; - - for( i = 0; i < FracCount; i++ ) - { - getFilter( i ); - } - } - - /** - * Function returns an approximate initialization complexity, expressed in - * the number of multiply-add operations. This includes fractional delay - * filters calculation and multiplication by an external filter. This - * function can only be called after the init() function. - * - * @param FracUseMap Fractional delays use map, each element corresponds - * to a single fractional delay, will be compared to the internal table - * fill flags. This map should include 0 and 1 values only. - * @return The complexity of the initialization, expressed in the number - * of multiply-add operations. - */ - - int calcInitComplexity( const CBuffer< uint8_t >& FracUseMap ) const - { - const int FltInitCost = 65; // Cost to initialize a single sample - // of the fractional delay filter. - const int FltUseCost = FilterLen * Order + - SrcFilterLen * ExtFilter.getCapacity(); // Cost to use a single - // fractional delay filter. - const int ucb[ 2 ] = { 0, FltUseCost }; - int ic; - int i; - - if( IsInitRequired ) - { - ic = FracCount * SrcFilterLen * FltInitCost; - - for( i = 0; i < FracCount; i++ ) - { - ic += ucb[ FracUseMap[ i ]]; - } - } - else - { - ic = 0; - - for( i = 0; i < FracCount; i++ ) - { - if( FracUseMap[ i ] != 0 ) - { - ic += ucb[ TableFillFlags[ i ] == 0 ? 1 : 0 ]; - } - } - } - - return( ic ); - } - -private: - static const int InterpPoints = 2; ///< The maximal number of points the - ///< interpolation is based on. - ///< - double WFLen2; ///< Window function's Len2 parameter. - ///< - double WFFreq; ///< Window function's Freq parameter. - ///< - double WFAlpha; ///< Window function's Alpha parameter. - ///< - int FracCount; ///< The required number of fractional delay filters. - ///< - int Order; ///< The order of the interpolation polynomial. - ///< - int Alignment; ///< The required filter table alignment. - ///< - int SrcFilterLen; ///< Length of the "source" filters. This is always an - ///< even value. - ///< - int FilterLen; ///< Specifies the number of samples (taps) each fractional - ///< delay filter has. This is always an even value, adjusted by the - ///< FltLenAlign. - ///< - int FilterSize; ///< The size of a single filter element, equals - ///< FilterLen * ElementSize. - ///< - bool IsInitRequired; ///< "True" if SrcTable filter table initialization - ///< is required. This value is available only after the call to the - ///< init() function. - ///< - CBuffer< fptype > Table; ///< Interpolation table, size equals to - ///< ReqFracCount * FilterLen * ElementSize. - ///< - CBuffer< uint8_t > TableFillFlags; ///< Contains ReqFracCount + 1 - ///< elements. Bit 0 of every element is 1 if Table already contains - ///< the filter from SrcTable filtered by ExtFilter. Bit 1 of every - ///< element means higher order coefficients were filled for the - ///< filter. - ///< - CFltBuffer ExtFilter; ///< External filter that should be applied to every - ///< fractional delay filter. Can be empty. Half of this filter's - ///< capacity is used as latency (group delay) value of the filter. - ///< - CBuffer< double > SrcTable; ///< Source table of delay filters, contains - ///< ReqFracCount + 1 elements. This table is used to fill the Table - ///< with the actual filters, filtered by an external filter. - ///< - bool IsSrcTableBuilt; ///< "True" if the SrcTable was built already. This - ///< variable is set to "false" in the init() function. - ///< - - /** - * Function builds source table used in the createFilter() function. - */ - - void buildSrcTable() - { - IsSrcTableBuilt = true; - IsInitRequired = false; - - CDSPPeakedCosineLPF p( WFLen2, WFFreq, WFAlpha ); - - const int BufLen = SrcFilterLen * FracCount + InterpPoints - 1; - const int BufOffs = InterpPoints / 2 - 1; - const int BufCenter = SrcFilterLen * FracCount / 2 + BufOffs; - - CBuffer< double > Buf( BufLen ); - memset( Buf, 0, ( BufCenter - p.fl2 ) * sizeof( double )); - int i = BufLen - BufCenter - p.fl2 - 1; - memset( &Buf[ BufLen - i ], 0, i * sizeof( double )); - - p.generateLPF( &Buf[ BufCenter - p.fl2 ], FracCount ); - - SrcTable.alloc(( FracCount + 1 ) * SrcFilterLen ); - TableFillFlags.alloc( FracCount + 1 ); - int j; - double* op0 = SrcTable; - - for( i = FracCount; i >= 0; i-- ) - { - TableFillFlags[ i ] = 0; - double* p = Buf + BufOffs + i; - - for( j = 0; j < SrcFilterLen; j++ ) - { - op0[ 0 ] = p[ 0 ]; - op0++; - p += FracCount; - } - } - - Table.alloc(( FracCount + 1 ) * FilterSize, Alignment ); - } - - /** - * Function creates the specified filter in the Table by copying it from - * the SrcTable and filtering by ExtFilter. Function does nothing if - * filter was already created. - * - * @param k Filter index to create, in the range 0 to FracCount, - * inclusive. - */ - - void createFilter( const int k ) - { - if( TableFillFlags[ k ] != 0 ) - { - return; - } - - TableFillFlags[ k ] |= 1; - const int ExtFilterLatency = ExtFilter.getCapacity() / 2; - const int ResLatency = ExtFilterLatency + SrcFilterLen / 2; - int ResLen = SrcFilterLen; - - if( ExtFilter.getCapacity() > 0 ) - { - ResLen += ExtFilter.getCapacity() - 1; - } - - const int ResOffs = FilterLen / 2 - ResLatency; - fptype* op = &Table[ k * FilterSize ]; - int i; - - for( i = 0; i < ResOffs; i++ ) - { - op[ i ] = 0.0; - } - - for( i = ResOffs + ResLen; i < FilterLen; i++ ) - { - op[ i ] = 0.0; - } - - op += ResOffs; - const double* const srcflt = &SrcTable[ k * SrcFilterLen ]; - - if( ExtFilter.getCapacity() == 0 ) - { - for( i = 0; i < ResLen; i++ ) - { - op[ i ] = (fptype) srcflt[ i ]; - } - - return; - } - - // Perform convolution of extflt and srcflt. - - const double* const extflt = &ExtFilter[ 0 ]; - int j; - - for( j = 0; j < ResLen; j++ ) - { - int k = 0; - int l = j - ExtFilter.getCapacity() + 1; - int r = l + ExtFilter.getCapacity(); - - if( l < 0 ) - { - k -= l; - l = 0; - } - - if( r > SrcFilterLen ) - { - r = SrcFilterLen; - } - - const double* const extfltb = extflt + k; - const double* const srcfltb = srcflt + l; - double s = 0.0; - l = r - l; - - for( i = 0; i < l; i++ ) - { - s += extfltb[ i ] * srcfltb[ i ]; - } - - op[ j ] = (fptype) s; - } - } -}; - -/** - * @brief Thread pool for multi-threaded image resizing operation. - * - * This base class is used to organize a multi-threaded image resizing - * operation. The thread pool should consist of threads that initially wait - * for a signal. Upon receiving a signal (via the startAllWorkloads() - * function) each previously added thread should execute its workload's - * process() function once, and return to the wait signal state again. The - * thread pool should be also able to efficiently wait for all workloads to - * finish via the waitAllWorkloadsToFinish() function. - * - * The image resizing algorithm makes calls to functions of this class. - */ - -class CImageResizerThreadPool -{ -public: - CImageResizerThreadPool() - { - } - - virtual ~CImageResizerThreadPool() - { - } - - /** - * @brief Thread pool's workload object class. - * - * This class should be used as a base class for objects that perform the - * actual work spread over several threads. - */ - - class CWorkload - { - public: - virtual ~CWorkload() - { - } - - /** - * Function that gets called from the thread when thread pool's - * startAllWorkloads() function is called. - */ - - virtual void process() = 0; - }; - - /** - * @return The suggested number of workloads (and their associated - * threads) to add. The minimal value this function can return is 1. The - * usual value may depend on the number of physical and virtual cores - * present in the system, and on other considerations. - */ - - virtual int getSuggestedWorkloadCount() const - { - return( 1 ); - } - - /** - * Function adds a new workload (and possibly thread) to the thread pool. - * The caller decides how many parallel workloads (and threads) it - * requires, but this number will not exceed the value returned by the - * getSuggestedWorkloadCount() function. It is implementation-specific how - * many workloads to associate with a single thread. But for efficiency - * reasons each workload should be associated with its own thread. - * - * Note that the same set of workload objects will be processed each time - * the startAllWorkloads() function is called. This means that workload - * objects are added only once. The caller changes the state of the - * workload objects and then calls the startAllWorkloads() function to - * process them. - * - * @param Workload Workload object whose process() function will be called - * from within the thread when the startAllWorkloads() function is called. - */ - - virtual void addWorkload( CWorkload* const Workload ) - { - } - - /** - * Function starts all workloads associated with threads previously added - * via the addWorkload() function. It is assumed that this function - * performs the necessary "memory barrier" (or "cache sync") kind of - * operation so that all threads catch up the prior changes made to the - * workload objects during their wait state. - */ - - virtual void startAllWorkloads() - { - } - - /** - * Function waits for all workloads to finish. - */ - - virtual void waitAllWorkloadsToFinish() - { - } - - /** - * Function removes all workloads previously added via the addWorkload() - * function. This function gets called only after the - * waitAllWorkloadsToFinish() function call. - */ - - virtual void removeAllWorkloads() - { - } -}; - -/** - * @brief Resizing algorithm parameters structure. - * - * This structure holds all selectable parameters used by the resizing - * algorithm at various stages, for both downsizing and upsizing. There are no - * other parameters exist that can optimize the performance of the resizing - * algorithm. Filter length parameters can take fractional values. - * - * Beside quality, these parameters (except Alpha parameters) directly affect - * the computative cost of the resizing algorithm. It is possible to trade - * the visual quality for computative cost. - * - * Anti-alias filtering during downsizing can be defined as a considerable - * reduction of contrast of smallest features of an image. Unfortunately, such - * de-contrasting partially affects features of all sizes thus producing a - * non-linearity of frequency response. All pre-defined parameter sets are - * described by 3 values separated by slashes. The first value is the - * de-contrasting factor of small features (which are being removed) while - * the second value is the de-contrasting factor of large features (which - * should remain intact), with value of 1 equating to "no contrast change". - * The third value is the optimization score (see below), with value of 0 - * equating to the "perfect" linearity of frequency response. - * - * The pre-defined parameter sets offered by this library were auto-optimized - * for the given LPFltBaseLen, IntFltLen and CorrFltAlpha values. The - * optimization goal was to minimize the score: the sum of squares of the - * difference between original and processed images (which was not actually - * resized, k=1). The original image was a 0.5 megapixel uniformly-distributed - * white-noise image with pixel intensities in the 0-1 range. Such goal - * converges very well and produces filtering system with the flattest - * frequency response possible for the given constraints. With this goal, - * increasing the LPFltBaseLen value reduces the general amount of aliasing - * artifacts. - */ - -struct CImageResizerParams -{ - double CorrFltAlpha; ///< Alpha parameter of the Peaked Cosine window - ///< function used on the correction filter. The "usable" values are - ///< in the narrow range 1.0 to 1.5. - ///< - double CorrFltLen; ///< Correction filter's length in samples (taps). The - ///< "usable" range is narrow, 5.5 to 8, as to minimize the - ///< "overcorrection" which is mathematically precise, but visually - ///< unacceptable. - ///< - double IntFltAlpha; ///< Alpha parameter of the Peaked Cosine window - ///< function used on the interpolation low-pass filter. The "usable" - ///< values are in the range 1.5 to 2.5. - ///< - double IntFltCutoff; ///< Interpolation low-pass filter's cutoff frequency - ///< (normalized, [0; 1]). The "usable" range is 0.6 to 0.8. - ///< - double IntFltLen; ///< Interpolation low-pass filter's length in samples - ///< (taps). The length value should be at least 18 or otherwise a - ///< "dark grid" artifact will be introduced if a further sharpening - ///< is applied. IntFltLen together with other IntFlt parameters - ///< should be tuned in a way that produces the flattest frequency - ///< response in 0-0.5 normalized frequency range (this range is due - ///< to 2X upsampling). - ///< - double LPFltAlpha; ///< Alpha parameter of the Peaked Cosine window - ///< function used on the low-pass filter. The "usable" values are - ///< in the range 1.5 to 6.5. - ///< - double LPFltBaseLen; ///< Base length of the low-pass (aka anti-aliasing - ///< or reconstruction) filter, in samples (taps), further adjusted by - ///< the actual cutoff frequency, upsampling and downsampling factors. - ///< The "usable" range is between 6 and 9. - ///< - double LPFltCutoffMult; ///< Low-pass filter's cutoff frequency - ///< multiplier. This value can be both below and above 1.0 as - ///< low-pass filters are inserted on downsampling and upsampling - ///< steps and always have corner frequency equal to or below 0.5pi. - ///< This multiplier shifts low-pass filter's corner frequency towards - ///< lower (if below 1.0) or higher (if above 1.0) frequencies. This - ///< multiplier can be way below 1.0 since any additional - ///< high-frequency damping will be partially corrected by the - ///< correction filter. The "usable" range is 0.3 to 1.0. - ///< - - CImageResizerParams() - : HBFltAlpha( 1.75395 ) - , HBFltCutoff( 0.40356 ) - , HBFltLen( 22.00000 ) - { - } - - double HBFltAlpha; ///< Half-band filter's Alpha. Assigned internally. - ///< - double HBFltCutoff; ///< Half-band filter's cutoff point [0; 1]. Assigned - ///< internally. - ///< - double HBFltLen; ///< Length of the half-band low-pass filter. Assigned - ///< internally. Internally used to perform 2X or higher downsampling. - ///< These filter parameters should be treated as "technical" and do - ///< not require adjustment as they were tuned to suit all - ///< combinations of other parameters. This half-band filter provides - ///< a wide transition band (for minimal ringing artifacts) and a high - ///< stop-band attenuation (for minimal aliasing). - ///< -}; - -/** - * @brief The default set of resizing algorithm parameters - * (10.01/1.029/0.019169). - * - * This is the default set of resizing parameters that was designed to deliver - * a sharp image while still providing a low amount of ringing artifacts, and - * having a reasonable computational cost. - */ - -struct CImageResizerParamsDef : public CImageResizerParams -{ - CImageResizerParamsDef() - { - CorrFltAlpha = 1.0;//10.01/1.88/1.029(522.43)/0.019169:258648,446808 - CorrFltLen = 6.30770; - IntFltAlpha = 2.27825; - IntFltCutoff = 0.75493; - IntFltLen = 18.0; - LPFltAlpha = 3.40127; - LPFltBaseLen = 7.78; - LPFltCutoffMult = 0.78797; - } -}; - -/** - * @brief Set of resizing algorithm parameters for ultra-low-ringing - * performance (7.69/1.069/0.000245). - * - * This set of resizing algorithm parameters offers the lowest amount of - * ringing this library is capable of providing while still offering a decent - * quality. Low ringing is attained at the expense of higher aliasing - * artifacts and a slightly reduced contrast. - */ - -struct CImageResizerParamsULR : public CImageResizerParams -{ - CImageResizerParamsULR() - { - CorrFltAlpha = 1.0;//7.69/1.97/1.069(31445.45)/0.000245:258627,436845 - CorrFltLen = 5.83280; - IntFltAlpha = 2.11453; - IntFltCutoff = 0.73986; - IntFltLen = 18.0; - LPFltAlpha = 1.73455; - LPFltBaseLen = 6.40; - LPFltCutoffMult = 0.61314; - } -}; - -/** - * @brief Set of resizing algorithm parameters for low-ringing performance - * (7.86/1.065/0.000106). - * - * This set of resizing algorithm parameters offers a very low-ringing - * performance at the expense of higher aliasing artifacts and a slightly - * reduced contrast. - */ - -struct CImageResizerParamsLR : public CImageResizerParams -{ - CImageResizerParamsLR() - { - CorrFltAlpha = 1.0;//7.86/1.96/1.065(73865.02)/0.000106:258636,437381 - CorrFltLen = 5.87671; - IntFltAlpha = 2.25322; - IntFltCutoff = 0.74090; - IntFltLen = 18.0; - LPFltAlpha = 1.79306; - LPFltBaseLen = 7.00; - LPFltCutoffMult = 0.68881; - } -}; - -/** - * @brief Set of resizing algorithm parameters for lower-ringing performance - * (8.86/1.046/0.010168). - * - * This set of resizing algorithm parameters offers a lower-ringing - * performance in comparison to the default setting, at the expense of higher - * aliasing artifacts and a slightly reduced contrast. - */ - -struct CImageResizerParamsLow : public CImageResizerParams -{ - CImageResizerParamsLow() - { - CorrFltAlpha = 1.0;//8.86/1.92/1.046(871.54)/0.010168:258647,442252 - CorrFltLen = 6.09757; - IntFltAlpha = 2.36704; - IntFltCutoff = 0.74674; - IntFltLen = 18.0; - LPFltAlpha = 2.19427; - LPFltBaseLen = 7.66; - LPFltCutoffMult = 0.75380; - } -}; - -/** - * @brief Set of resizing algorithm parameters for low-aliasing - * resizing (11.81/1.012/0.038379). - * - * This set of resizing algorithm parameters offers a considerable - * anti-aliasing performance with a good frequency response linearity (and - * contrast). This is an intermediate setting between the default and Ultra - * parameters. - */ - -struct CImageResizerParamsHigh : public CImageResizerParams -{ - CImageResizerParamsHigh() - { - CorrFltAlpha = 1.0;//11.81/1.83/1.012(307.84)/0.038379:258660,452719 - CorrFltLen = 6.80909; - IntFltAlpha = 2.44917; - IntFltCutoff = 0.75856; - IntFltLen = 18.0; - LPFltAlpha = 4.39527; - LPFltBaseLen = 8.18; - LPFltCutoffMult = 0.79172; - } -}; - -/** - * @brief Set of resizing algorithm parameters for ultra low-aliasing - * resizing (13.65/1.001/0.000483). - * - * This set of resizing algorithm parameters offers a very considerable - * anti-aliasing performance with a good frequency response linearity (and - * contrast). This set of parameters is computationally expensive and may - * produce ringing artifacts on sharp features. - */ - -struct CImageResizerParamsUltra : public CImageResizerParams -{ - CImageResizerParamsUltra() - { - CorrFltAlpha = 1.0;//13.65/1.79/1.001(28288.41)/0.000483:258658,457974 - CorrFltLen = 7.48060; - IntFltAlpha = 1.93750; - IntFltCutoff = 0.75462; - IntFltLen = 18.0; - LPFltAlpha = 5.55209; - LPFltBaseLen = 8.34; - LPFltCutoffMult = 0.78002; - } -}; - -/** - * @brief Image resizing variables class. - * - * This is an utility "catch all" class that defines various variables used - * during image resizing. Several variables that are explicitly initialized in - * this class' constructor are also used as additional "input" variables to - * the image resizing function. These variables will not be changed by the - * avir::CImageResizer<>::resizeImage() function. - */ - -class CImageResizerVars -{ -public: - int ElCount; ///< The number of "fptype" elements used to store 1 pixel. - ///< - int ElCountIO; ///< The number of source and destination image's elements - ///< used to store 1 pixel. - ///< - int fppack; ///< The number of atomic types stored in a single "fptype" - ///< element. - ///< - int fpalign; ///< Suggested alignment size in bytes. This is not a - ///< required alignment, because image resizing algorithm cannot be - ///< made to have a strictly aligned data access in all cases (e.g. - ///< de-interleaved interpolation cannot perform aligned accesses). - ///< - int elalign; ///< Length alignment of arrays of elements. This applies to - ///< filters and intermediate buffers: this constant forces filters - ///< and scanlines to have a length which is a multiple of this value, - ///< for more efficient SIMD implementation. - ///< - int packmode; ///< 0 if interleaved packing, 1 if de-interleaved. - ///< - int BufLen[ 2 ]; ///< Intermediate buffers' lengths in "fptype" elements. - int BufOffs[ 2 ]; ///< Offsets into the intermediate buffers, used to - ///< provide prefix elements required during processing so that no - ///< "out of range" access happens. This offset is a multiple of - ///< ElCount if pixels are stored in interleaved form. - ///< - double k; ///< Resizing step coefficient, updated to reflect the actually - ///< used coefficient during resizing. - ///< - double o; ///< Starting pixel offset inside the source image, updated to - ///< reflect the actually used offset during resizing. - ///< - int ResizeStep; ///< Index of the resizing step in the latest filtering - ///< steps array. - ///< - double InGammaMult; ///< Input gamma multiplier, used to convert input - ///< data to 0 to 1 range. 0.0 if no gamma is in use. - ///< - double OutGammaMult; ///< Output gamma multiplier, used to convert data to - ///< 0 to 255/65535 range. 0.0 if no gamma is in use. - ///< - - double ox; ///< Start X pixel offset within source image (can be - ///< negative). Positive offset moves image to the left. - ///< - double oy; ///< Start Y pixel offset within source image (can be - ///< negative). Positive offset moves image to the top. - ///< - CImageResizerThreadPool* ThreadPool; ///< Thread pool to be used by the - ///< image resizing function. Set to NULL to use single-threaded - ///< processing. - ///< - bool UseSRGBGamma; ///< Perform sRGB gamma linearization (correction). - ///< - int BuildMode; ///< The build mode to use, for debugging purposes. Set to - ///< -1 to select a minimal-complexity mode automatically. All build - ///< modes deliver similar results with minor deviations. - ///< - int RndSeed; ///< Random seed parameter. This parameter may be incremented - ///< after each random generator initialization. The use of this - ///< variable depends on the ditherer implementation. - ///< - - CImageResizerVars() - : ox( 0.0 ) - , oy( 0.0 ) - , ThreadPool( nullptr ) - , UseSRGBGamma( false ) - , BuildMode( -1 ) - , RndSeed( 0 ) - { - } -}; - -/** - * @brief Image resizer's filtering step class. - * - * Class defines data to perform a single filtering step over a whole - * horizontal or vertical scanline. Resizing consists of 1 or more steps that - * may be performed before the actual resizing takes place. Filtering may also - * follow a resizing step. Each step must ensure that scanline data contains - * enough pixels to perform the next step (which may be resizing) without - * exceeding scanline's bounds. - * - * A derived class must implement several "const" and "static" functions that - * are used to perform the actual filtering in interleaved or de-interleaved - * mode. - * - * @tparam fptype Floating point type to use for storing pixel elements. SIMD - * types can be used: in this case each element may hold a whole pixel. - * @tparam fptypeatom The atomic type the "fptype" consists of. - */ - -template< class fptype, class fptypeatom > -class CImageResizerFilterStep -{ -public: - bool IsUpsample; ///< "True" if this step is an upsampling step, "false" - ///< if downsampling step. Should be set to "false" if ResampleFactor - ///< equals 0. - ///< - int ResampleFactor; ///< Resample factor (>=1). If 0, this is a resizing - ///< step. This value should be >1 if IsUpsample equals "true". - ///< - CBuffer< fptype > Flt; ///< Filter to use at this step. - ///< - CFltBuffer FltOrig; ///< Originally-designed filter. This buffer may not - ///< be assigned. Assigned by filters that precede the resizing step - ///< if such filter is planned to be embedded into the interpolation - ///< filter as "external" filter. If IsUpsample=true and this filter - ///< buffer is not empty, the upsampling step will not itself apply - ///< any filtering over upsampled input scanline. - ///< - double DCGain; ///< DC gain which was applied to the filter. Not defined - ///< if ResampleFactor = 0. - ///< - int FltLatency; ///< Filter's latency (group delay, shift) in pixels. - ///< - const CImageResizerVars* Vars; ///< Image resizing-related variables. - ///< - int InLen; ///< Input scanline's length in pixels. - ///< - int InBuf; ///< Input buffer index, 0 or 1. - ///< - int InPrefix; ///< Required input prefix pixels. These prefix pixels will - ///< be filled with source scanline's first pixel value. If IsUpsample - ///< is "true", this is the additional number of times the first pixel - ///< will be filtered before processing scanline, this number is also - ///< reflected in the OutPrefix. - ///< - int InSuffix; ///< Required input suffix pixels. These suffix pixels will - ///< be filled with source scanline's last pixel value. If IsUpsample - ///< is "true", this is the additional number of times the last pixel - ///< will be filtered before processing scanline, this number is also - ///< reflected in the OutSuffix. - ///< - int InElIncr; ///< Pixel element increment within the input buffer, used - ///< during de-interleaved processing: in this case each image's - ///< channel is stored independently, InElIncr elements apart. - ///< - int OutLen; ///< Length of the resulting scanline. - ///< - int OutBuf; ///< Output buffer index. 0 or 1; 2 for the last step. - ///< - int OutPrefix; ///< Required output prefix pixels. These prefix pixels - ///< will not be pre-filled with any values. Value is valid only if - ///< IsUpsample equals "true". - ///< - int OutSuffix; ///< Required input suffix pixels. These suffix pixels will - ///< not be pre-filled with any values. Value is valid only if - ///< IsUpsample equals "true". - ///< - int OutElIncr; ///< Pixel element increment within the output buffer, used - ///< during de-interleaved processing. Equals to the InBufElIncr of - ///< the next step. - ///< - CBuffer< fptype > PrefixDC; ///< DC component fluctuations added at the - ///< start of the resulting scanline, used when IsUpsample equals - ///< "true". - ///< - CBuffer< fptype > SuffixDC; ///< DC component fluctuations added at the - ///< end of the resulting scanline, used when IsUpsample equals - ///< "true". - ///< - int EdgePixelCount; ///< The number of edge pixels added. Affects the - ///< initial position within the input scanline, used to produce edge - ///< pixels. This variable is used and should be defined when - ///< IsUpsample=false and ResampleFactor>0. When assigning this - ///< variable it is also necessary to update InPrefix, OutLen and - ///< Vars.o variables. - ///< - static const int EdgePixelCountDef = 3; ///< The default number of pixels - ///< additionally produced at scanline edges during filtering. This is - ///< required to reduce edge artifacts. - ///< - - /** - * @brief Resizing position structure. - * - * Structure holds resizing position and pointer to fractional delay - * filter. - */ - - struct CResizePos - { - int SrcPosInt; ///< Source scanline position. - ///< - int fti; ///< Fractional delay filter index. - ///< - const fptype* ftp; ///< Fractional delay filter pointer. - ///< - fptypeatom x; ///< Interpolation coefficient between delay filters. - ///< - int SrcOffs; ///< Source scanline offset. - ///< - }; - - /** - * @brief Resizing positions buffer class. - * - * This class combines buffer together with variables that define resizing - * stepping. - */ - - class CRPosBuf : public CBuffer< CResizePos > - { - public: - double k; ///< Resizing step. - ///< - double o; ///< Resizing offset. - ///< - int FracCount; ///< The number of fractional delay filters in a filter - ///< bank used together with this buffer. - ///< - }; - - /** - * @brief Resizing positions buffer array class. - * - * This class combines structure array of the CRPosBuf class objects with - * the function that locates or creates buffer with the required resizing - * stepping. - */ - - class CRPosBufArray : public CStructArray< CRPosBuf > - { - public: - using CStructArray< CRPosBuf > :: add; - using CStructArray< CRPosBuf > :: getItemCount; - - /** - * Function returns the resizing positions buffer with the required - * stepping. If no such buffer exists, it is created. - * - * @param k Resizing step. - * @param o Resizing offset. - * @param FracCount The number of fractional delay filters in a filter - * bank used together with this buffer. - * @return Reference to the CRPosBuf object. - */ - - CRPosBuf& getRPosBuf( const double k, const double o, - const int FracCount ) - { - int i; - - for( i = 0; i < getItemCount(); i++ ) - { - CRPosBuf& Buf = (*this)[ i ]; - - if( Buf.k == k && Buf.o == o && Buf.FracCount == FracCount ) - { - return( Buf ); - } - } - - CRPosBuf& NewBuf = add(); - NewBuf.k = k; - NewBuf.o = o; - NewBuf.FracCount = FracCount; - - return( NewBuf ); - } - }; - - CRPosBuf* RPosBuf; ///< Resizing positions buffer. Used when - ///< ResampleFactor equals 0 (resizing step). - ///< - CDSPFracFilterBankLin< fptype >* FltBank; ///< Filter bank in use by *this - ///< resizing step. - ///< -}; - -/** - * @brief Interleaved filtering steps implementation class. - * - * This class implements scanline filtering functions in interleaved mode. - * This means that each pixel is processed independently, not in groups. - * - * @tparam fptype Floating point type to use for storing pixel elements. SIMD - * types can be used: in this case each element may hold a whole pixel. - * @tparam fptypeatom The atomic type the "fptype" consists of. - */ - -template< class fptype, class fptypeatom > -class CImageResizerFilterStepINL : - public CImageResizerFilterStep< fptype, fptypeatom > -{ -public: - using CImageResizerFilterStep< fptype, fptypeatom > :: IsUpsample; - using CImageResizerFilterStep< fptype, fptypeatom > :: ResampleFactor; - using CImageResizerFilterStep< fptype, fptypeatom > :: Flt; - using CImageResizerFilterStep< fptype, fptypeatom > :: FltOrig; - using CImageResizerFilterStep< fptype, fptypeatom > :: FltLatency; - using CImageResizerFilterStep< fptype, fptypeatom > :: Vars; - using CImageResizerFilterStep< fptype, fptypeatom > :: InLen; - using CImageResizerFilterStep< fptype, fptypeatom > :: InPrefix; - using CImageResizerFilterStep< fptype, fptypeatom > :: InSuffix; - using CImageResizerFilterStep< fptype, fptypeatom > :: OutLen; - using CImageResizerFilterStep< fptype, fptypeatom > :: OutPrefix; - using CImageResizerFilterStep< fptype, fptypeatom > :: OutSuffix; - using CImageResizerFilterStep< fptype, fptypeatom > :: PrefixDC; - using CImageResizerFilterStep< fptype, fptypeatom > :: SuffixDC; - using CImageResizerFilterStep< fptype, fptypeatom > :: RPosBuf; - using CImageResizerFilterStep< fptype, fptypeatom > :: FltBank; - using CImageResizerFilterStep< fptype, fptypeatom > :: EdgePixelCount; - - /** - * Function performs "packing" of a scanline and type conversion. - * Scanline, depending on the "fptype" can be potentially stored as a - * packed SIMD values having a certain atomic type. If required, the sRGB - * gamma correction is applied. - * - * @param ip Input scanline. - * @param op0 Output scanline. - * @param l0 The number of pixels to "pack". - */ - - template< class Tin > - void packScanline( const Tin* ip, fptype* const op0, const int l0 ) const - { - const int ElCount = Vars -> ElCount; - const int ElCountIO = Vars -> ElCountIO; - fptype* op = op0; - int l = l0; - - if( !Vars -> UseSRGBGamma ) - { - if( ElCountIO == 1 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) op; - v[ 0 ] = (fptypeatom) ip[ 0 ]; - op += ElCount; - ip++; - l--; - } - } - else - if( ElCountIO == 4 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) op; - v[ 0 ] = (fptypeatom) ip[ 0 ]; - v[ 1 ] = (fptypeatom) ip[ 1 ]; - v[ 2 ] = (fptypeatom) ip[ 2 ]; - v[ 3 ] = (fptypeatom) ip[ 3 ]; - op += ElCount; - ip += 4; - l--; - } - } - else - if( ElCountIO == 3 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) op; - v[ 0 ] = (fptypeatom) ip[ 0 ]; - v[ 1 ] = (fptypeatom) ip[ 1 ]; - v[ 2 ] = (fptypeatom) ip[ 2 ]; - op += ElCount; - ip += 3; - l--; - } - } - else - if( ElCountIO == 2 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) op; - v[ 0 ] = (fptypeatom) ip[ 0 ]; - v[ 1 ] = (fptypeatom) ip[ 1 ]; - op += ElCount; - ip += 2; - l--; - } - } - } - else - { - const fptypeatom gm = (fptypeatom) Vars -> InGammaMult; - - if( ElCountIO == 1 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) op; - v[ 0 ] = convertSRGB2Lin( (fptypeatom) ip[ 0 ] * gm ); - op += ElCount; - ip++; - l--; - } - } - else - if( ElCountIO == 4 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) op; - v[ 0 ] = convertSRGB2Lin( (fptypeatom) ip[ 0 ] * gm ); - v[ 1 ] = convertSRGB2Lin( (fptypeatom) ip[ 1 ] * gm ); - v[ 2 ] = convertSRGB2Lin( (fptypeatom) ip[ 2 ] * gm ); - v[ 3 ] = convertSRGB2Lin( (fptypeatom) ip[ 3 ] * gm ); - op += ElCount; - ip += 4; - l--; - } - } - else - if( ElCountIO == 3 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) op; - v[ 0 ] = convertSRGB2Lin( (fptypeatom) ip[ 0 ] * gm ); - v[ 1 ] = convertSRGB2Lin( (fptypeatom) ip[ 1 ] * gm ); - v[ 2 ] = convertSRGB2Lin( (fptypeatom) ip[ 2 ] * gm ); - op += ElCount; - ip += 3; - l--; - } - } - else - if( ElCountIO == 2 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) op; - v[ 0 ] = convertSRGB2Lin( (fptypeatom) ip[ 0 ] * gm ); - v[ 1 ] = convertSRGB2Lin( (fptypeatom) ip[ 1 ] * gm ); - op += ElCount; - ip += 2; - l--; - } - } - } - - const int ZeroCount = ElCount * Vars -> fppack - ElCountIO; - op = op0; - l = l0; - - if( ZeroCount == 1 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) op + ElCountIO; - v[ 0 ] = (fptypeatom) 0; - op += ElCount; - l--; - } - } - else - if( ZeroCount == 2 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) op + ElCountIO; - v[ 0 ] = (fptypeatom) 0; - v[ 1 ] = (fptypeatom) 0; - op += ElCount; - l--; - } - } - else - if( ZeroCount == 3 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) op + ElCountIO; - v[ 0 ] = (fptypeatom) 0; - v[ 1 ] = (fptypeatom) 0; - v[ 2 ] = (fptypeatom) 0; - op += ElCount; - l--; - } - } - } - - /** - * Function applies Linear to sRGB gamma correction to the specified - * scanline. - * - * @param p Scanline. - * @param l The number of pixels to de-linearize. - * @param Vars0 Image resizing-related variables. - */ - - static void applySRGBGamma( fptype* p, int l, - const CImageResizerVars& Vars0 ) - { - const int ElCount = Vars0.ElCount; - const int ElCountIO = Vars0.ElCountIO; - const fptypeatom gm = (fptypeatom) Vars0.OutGammaMult; - - if( ElCountIO == 1 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) p; - v[ 0 ] = convertLin2SRGB( v[ 0 ]) * gm; - p += ElCount; - l--; - } - } - else - if( ElCountIO == 4 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) p; - v[ 0 ] = convertLin2SRGB( v[ 0 ]) * gm; - v[ 1 ] = convertLin2SRGB( v[ 1 ]) * gm; - v[ 2 ] = convertLin2SRGB( v[ 2 ]) * gm; - v[ 3 ] = convertLin2SRGB( v[ 3 ]) * gm; - p += ElCount; - l--; - } - } - else - if( ElCountIO == 3 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) p; - v[ 0 ] = convertLin2SRGB( v[ 0 ]) * gm; - v[ 1 ] = convertLin2SRGB( v[ 1 ]) * gm; - v[ 2 ] = convertLin2SRGB( v[ 2 ]) * gm; - p += ElCount; - l--; - } - } - else - if( ElCountIO == 2 ) - { - while( l > 0 ) - { - fptypeatom* v = (fptypeatom*) p; - v[ 0 ] = convertLin2SRGB( v[ 0 ]) * gm; - v[ 1 ] = convertLin2SRGB( v[ 1 ]) * gm; - p += ElCount; - l--; - } - } - } - - /** - * Function converts vertical scanline to horizontal scanline. This - * function is called by the image resizer when image is resized - * vertically. This means that the vertical scanline is stored in the - * same format produced by the packScanline() and maintained by other - * filtering functions. - * - * @param ip Input vertical scanline. - * @param op Output buffer (temporary buffer used during resizing). - * @param SrcLen The number of pixels in the input scanline, also used to - * calculate input buffer increment. - * @param SrcIncr Input buffer increment to the next vertical pixel. - */ - - void convertVtoH( const fptype* ip, fptype* op, const int SrcLen, - const int SrcIncr ) const - { - const int ElCount = Vars -> ElCount; - int j; - - if( ElCount == 1 ) - { - for( j = 0; j < SrcLen; j++ ) - { - op[ 0 ] = ip[ 0 ]; - ip += SrcIncr; - op++; - } - } - else - if( ElCount == 4 ) - { - for( j = 0; j < SrcLen; j++ ) - { - op[ 0 ] = ip[ 0 ]; - op[ 1 ] = ip[ 1 ]; - op[ 2 ] = ip[ 2 ]; - op[ 3 ] = ip[ 3 ]; - ip += SrcIncr; - op += 4; - } - } - else - if( ElCount == 3 ) - { - for( j = 0; j < SrcLen; j++ ) - { - op[ 0 ] = ip[ 0 ]; - op[ 1 ] = ip[ 1 ]; - op[ 2 ] = ip[ 2 ]; - ip += SrcIncr; - op += 3; - } - } - else - if( ElCount == 2 ) - { - for( j = 0; j < SrcLen; j++ ) - { - op[ 0 ] = ip[ 0 ]; - op[ 1 ] = ip[ 1 ]; - ip += SrcIncr; - op += 2; - } - } - } - - /** - * Function performs "unpacking" of a scanline and type conversion - * (truncation is used when floating point is converted to integer). - * Scanline, depending on the "fptype" can be potentially stored as a - * packed SIMD values having a certain atomic type. The unpacking function - * assumes that scanline is stored in the style produced by the - * packScanline() function. - * - * @param ip Input scanline. - * @param op Output scanline. - * @param l The number of pixels to "unpack". - * @param Vars0 Image resizing-related variables. - */ - - template< class Tout > - static void unpackScanline( const fptype* ip, Tout* op, int l, - const CImageResizerVars& Vars0 ) - { - const int ElCount = Vars0.ElCount; - const int ElCountIO = Vars0.ElCountIO; - - if( ElCountIO == 1 ) - { - while( l > 0 ) - { - const fptypeatom* v = (const fptypeatom*) ip; - op[ 0 ] = (Tout) v[ 0 ]; - ip += ElCount; - op++; - l--; - } - } - else - if( ElCountIO == 4 ) - { - while( l > 0 ) - { - const fptypeatom* v = (const fptypeatom*) ip; - op[ 0 ] = (Tout) v[ 0 ]; - op[ 1 ] = (Tout) v[ 1 ]; - op[ 2 ] = (Tout) v[ 2 ]; - op[ 3 ] = (Tout) v[ 3 ]; - ip += ElCount; - op += 4; - l--; - } - } - else - if( ElCountIO == 3 ) - { - while( l > 0 ) - { - const fptypeatom* v = (const fptypeatom*) ip; - op[ 0 ] = (Tout) v[ 0 ]; - op[ 1 ] = (Tout) v[ 1 ]; - op[ 2 ] = (Tout) v[ 2 ]; - ip += ElCount; - op += 3; - l--; - } - } - else - if( ElCountIO == 2 ) - { - while( l > 0 ) - { - const fptypeatom* v = (const fptypeatom*) ip; - op[ 0 ] = (Tout) v[ 0 ]; - op[ 1 ] = (Tout) v[ 1 ]; - ip += ElCount; - op += 2; - l--; - } - } - } - - /** - * Function prepares input scanline buffer for *this filtering step. - * Left- and right-most pixels are replicated to make sure no buffer - * overrun happens. Such approach also allows to bypass any pointer - * range checks. - * - * @param Src Source buffer. - */ - - void prepareInBuf( fptype* Src ) const - { - if( IsUpsample || InPrefix + InSuffix == 0 ) - { - return; - } - - const int ElCount = Vars -> ElCount; - replicateArray( Src, ElCount, Src - ElCount, InPrefix, -ElCount ); - - Src += ( InLen - 1 ) * ElCount; - replicateArray( Src, ElCount, Src + ElCount, InSuffix, ElCount ); - } - - /** - * Function peforms scanline upsampling with filtering. - * - * @param Src Source scanline buffer (length = this -> InLen). Source - * scanline increment will be equal to ElCount. - * @param Dst Destination scanline buffer. - */ - - void doUpsample( const fptype* const Src, fptype* const Dst ) const - { - const int ElCount = Vars -> ElCount; - fptype* op0 = &Dst[ -OutPrefix * ElCount ]; - memset( op0, 0, ( OutPrefix + OutLen + OutSuffix ) * ElCount * - sizeof( fptype )); - - const fptype* ip = Src; - const int opstep = ElCount * ResampleFactor; - int l; - - if( FltOrig.getCapacity() > 0 ) - { - // Do not perform filtering, only upsample. - - op0 += ( OutPrefix % ResampleFactor ) * ElCount; - l = OutPrefix / ResampleFactor; - - if( ElCount == 1 ) - { - while( l > 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0 += opstep; - l--; - } - - l = InLen - 1; - - while( l > 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0 += opstep; - ip += ElCount; - l--; - } - - l = OutSuffix / ResampleFactor; - - while( l >= 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0 += opstep; - l--; - } - } - else - if( ElCount == 4 ) - { - while( l > 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0[ 1 ] = ip[ 1 ]; - op0[ 2 ] = ip[ 2 ]; - op0[ 3 ] = ip[ 3 ]; - op0 += opstep; - l--; - } - - l = InLen - 1; - - while( l > 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0[ 1 ] = ip[ 1 ]; - op0[ 2 ] = ip[ 2 ]; - op0[ 3 ] = ip[ 3 ]; - op0 += opstep; - ip += ElCount; - l--; - } - - l = OutSuffix / ResampleFactor; - - while( l >= 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0[ 1 ] = ip[ 1 ]; - op0[ 2 ] = ip[ 2 ]; - op0[ 3 ] = ip[ 3 ]; - op0 += opstep; - l--; - } - } - else - if( ElCount == 3 ) - { - while( l > 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0[ 1 ] = ip[ 1 ]; - op0[ 2 ] = ip[ 2 ]; - op0 += opstep; - l--; - } - - l = InLen - 1; - - while( l > 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0[ 1 ] = ip[ 1 ]; - op0[ 2 ] = ip[ 2 ]; - op0 += opstep; - ip += ElCount; - l--; - } - - l = OutSuffix / ResampleFactor; - - while( l >= 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0[ 1 ] = ip[ 1 ]; - op0[ 2 ] = ip[ 2 ]; - op0 += opstep; - l--; - } - } - else - if( ElCount == 2 ) - { - while( l > 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0[ 1 ] = ip[ 1 ]; - op0 += opstep; - l--; - } - - l = InLen - 1; - - while( l > 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0[ 1 ] = ip[ 1 ]; - op0 += opstep; - ip += ElCount; - l--; - } - - l = OutSuffix / ResampleFactor; - - while( l >= 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0[ 1 ] = ip[ 1 ]; - op0 += opstep; - l--; - } - } - - return; - } - - const fptype* const f = Flt; - const int flen = Flt.getCapacity(); - fptype* op; - int i; - - if( ElCount == 1 ) - { - l = InPrefix; - - while( l > 0 ) - { - op = op0; - - for( i = 0; i < flen; i++ ) - { - op[ i ] += f[ i ] * ip[ 0 ]; - } - - op0 += opstep; - l--; - } - - l = InLen - 1; - - while( l > 0 ) - { - op = op0; - - for( i = 0; i < flen; i++ ) - { - op[ i ] += f[ i ] * ip[ 0 ]; - } - - ip += ElCount; - op0 += opstep; - l--; - } - - l = InSuffix; - - while( l >= 0 ) - { - op = op0; - - for( i = 0; i < flen; i++ ) - { - op[ i ] += f[ i ] * ip[ 0 ]; - } - - op0 += opstep; - l--; - } - } - else - if( ElCount == 4 ) - { - l = InPrefix; - - while( l > 0 ) - { - op = op0; - - for( i = 0; i < flen; i++ ) - { - op[ 0 ] += f[ i ] * ip[ 0 ]; - op[ 1 ] += f[ i ] * ip[ 1 ]; - op[ 2 ] += f[ i ] * ip[ 2 ]; - op[ 3 ] += f[ i ] * ip[ 3 ]; - op += 4; - } - - op0 += opstep; - l--; - } - - l = InLen - 1; - - while( l > 0 ) - { - op = op0; - - for( i = 0; i < flen; i++ ) - { - op[ 0 ] += f[ i ] * ip[ 0 ]; - op[ 1 ] += f[ i ] * ip[ 1 ]; - op[ 2 ] += f[ i ] * ip[ 2 ]; - op[ 3 ] += f[ i ] * ip[ 3 ]; - op += 4; - } - - ip += ElCount; - op0 += opstep; - l--; - } - - l = InSuffix; - - while( l >= 0 ) - { - op = op0; - - for( i = 0; i < flen; i++ ) - { - op[ 0 ] += f[ i ] * ip[ 0 ]; - op[ 1 ] += f[ i ] * ip[ 1 ]; - op[ 2 ] += f[ i ] * ip[ 2 ]; - op[ 3 ] += f[ i ] * ip[ 3 ]; - op += 4; - } - - op0 += opstep; - l--; - } - } - else - if( ElCount == 3 ) - { - l = InPrefix; - - while( l > 0 ) - { - op = op0; - - for( i = 0; i < flen; i++ ) - { - op[ 0 ] += f[ i ] * ip[ 0 ]; - op[ 1 ] += f[ i ] * ip[ 1 ]; - op[ 2 ] += f[ i ] * ip[ 2 ]; - op += 3; - } - - op0 += opstep; - l--; - } - - l = InLen - 1; - - while( l > 0 ) - { - op = op0; - - for( i = 0; i < flen; i++ ) - { - op[ 0 ] += f[ i ] * ip[ 0 ]; - op[ 1 ] += f[ i ] * ip[ 1 ]; - op[ 2 ] += f[ i ] * ip[ 2 ]; - op += 3; - } - - ip += ElCount; - op0 += opstep; - l--; - } - - l = InSuffix; - - while( l >= 0 ) - { - op = op0; - - for( i = 0; i < flen; i++ ) - { - op[ 0 ] += f[ i ] * ip[ 0 ]; - op[ 1 ] += f[ i ] * ip[ 1 ]; - op[ 2 ] += f[ i ] * ip[ 2 ]; - op += 3; - } - - op0 += opstep; - l--; - } - } - else - if( ElCount == 2 ) - { - l = InPrefix; - - while( l > 0 ) - { - op = op0; - - for( i = 0; i < flen; i++ ) - { - op[ 0 ] += f[ i ] * ip[ 0 ]; - op[ 1 ] += f[ i ] * ip[ 1 ]; - op += 2; - } - - op0 += opstep; - l--; - } - - l = InLen - 1; - - while( l > 0 ) - { - op = op0; - - for( i = 0; i < flen; i++ ) - { - op[ 0 ] += f[ i ] * ip[ 0 ]; - op[ 1 ] += f[ i ] * ip[ 1 ]; - op += 2; - } - - ip += ElCount; - op0 += opstep; - l--; - } - - l = InSuffix; - - while( l >= 0 ) - { - op = op0; - - for( i = 0; i < flen; i++ ) - { - op[ 0 ] += f[ i ] * ip[ 0 ]; - op[ 1 ] += f[ i ] * ip[ 1 ]; - op += 2; - } - - op0 += opstep; - l--; - } - } - - op = op0; - const fptype* dc = SuffixDC; - l = SuffixDC.getCapacity(); - - if( ElCount == 1 ) - { - for( i = 0; i < l; i++ ) - { - op[ i ] += ip[ 0 ] * dc[ i ]; - } - } - else - if( ElCount == 4 ) - { - while( l > 0 ) - { - op[ 0 ] += ip[ 0 ] * dc[ 0 ]; - op[ 1 ] += ip[ 1 ] * dc[ 0 ]; - op[ 2 ] += ip[ 2 ] * dc[ 0 ]; - op[ 3 ] += ip[ 3 ] * dc[ 0 ]; - dc++; - op += 4; - l--; - } - } - else - if( ElCount == 3 ) - { - while( l > 0 ) - { - op[ 0 ] += ip[ 0 ] * dc[ 0 ]; - op[ 1 ] += ip[ 1 ] * dc[ 0 ]; - op[ 2 ] += ip[ 2 ] * dc[ 0 ]; - dc++; - op += 3; - l--; - } - } - else - if( ElCount == 2 ) - { - while( l > 0 ) - { - op[ 0 ] += ip[ 0 ] * dc[ 0 ]; - op[ 1 ] += ip[ 1 ] * dc[ 0 ]; - dc++; - op += 2; - l--; - } - } - - ip = Src; - op = Dst - InPrefix * opstep; - dc = PrefixDC; - l = PrefixDC.getCapacity(); - - if( ElCount == 1 ) - { - for( i = 0; i < l; i++ ) - { - op[ i ] += ip[ 0 ] * dc[ i ]; - } - } - else - if( ElCount == 4 ) - { - while( l > 0 ) - { - op[ 0 ] += ip[ 0 ] * dc[ 0 ]; - op[ 1 ] += ip[ 1 ] * dc[ 0 ]; - op[ 2 ] += ip[ 2 ] * dc[ 0 ]; - op[ 3 ] += ip[ 3 ] * dc[ 0 ]; - dc++; - op += 4; - l--; - } - } - else - if( ElCount == 3 ) - { - while( l > 0 ) - { - op[ 0 ] += ip[ 0 ] * dc[ 0 ]; - op[ 1 ] += ip[ 1 ] * dc[ 0 ]; - op[ 2 ] += ip[ 2 ] * dc[ 0 ]; - dc++; - op += 3; - l--; - } - } - else - if( ElCount == 2 ) - { - while( l > 0 ) - { - op[ 0 ] += ip[ 0 ] * dc[ 0 ]; - op[ 1 ] += ip[ 1 ] * dc[ 0 ]; - dc++; - op += 2; - l--; - } - } - } - - /** - * Function peforms scanline filtering with optional downsampling. - * Function makes use of the symmetry of the filter. - * - * @param Src Source scanline buffer (length = this -> InLen). Source - * scanline increment will be equal to ElCount. - * @param Dst Destination scanline buffer. - * @param DstIncr Destination scanline buffer increment, used for - * horizontal or vertical scanline stepping. - */ - - void doFilter( const fptype* const Src, fptype* Dst, - const int DstIncr ) const - { - const int ElCount = Vars -> ElCount; - const fptype* const f = &Flt[ FltLatency ]; - const int flen = FltLatency + 1; - const int ipstep = ElCount * ResampleFactor; - const fptype* ip = Src - EdgePixelCount * ipstep; - const fptype* ip1; - const fptype* ip2; - int l = OutLen; - int i; - - if( ElCount == 1 ) - { - while( l > 0 ) - { - fptype s = f[ 0 ] * ip[ 0 ]; - ip1 = ip; - ip2 = ip; - - for( i = 1; i < flen; i++ ) - { - ip1++; - ip2--; - s += f[ i ] * ( ip1[ 0 ] + ip2[ 0 ]); - } - - Dst[ 0 ] = s; - Dst += DstIncr; - ip += ipstep; - l--; - } - } - else - if( ElCount == 4 ) - { - while( l > 0 ) - { - fptype s1 = f[ 0 ] * ip[ 0 ]; - fptype s2 = f[ 0 ] * ip[ 1 ]; - fptype s3 = f[ 0 ] * ip[ 2 ]; - fptype s4 = f[ 0 ] * ip[ 3 ]; - ip1 = ip; - ip2 = ip; - - for( i = 1; i < flen; i++ ) - { - ip1 += 4; - ip2 -= 4; - s1 += f[ i ] * ( ip1[ 0 ] + ip2[ 0 ]); - s2 += f[ i ] * ( ip1[ 1 ] + ip2[ 1 ]); - s3 += f[ i ] * ( ip1[ 2 ] + ip2[ 2 ]); - s4 += f[ i ] * ( ip1[ 3 ] + ip2[ 3 ]); - } - - Dst[ 0 ] = s1; - Dst[ 1 ] = s2; - Dst[ 2 ] = s3; - Dst[ 3 ] = s4; - Dst += DstIncr; - ip += ipstep; - l--; - } - } - else - if( ElCount == 3 ) - { - while( l > 0 ) - { - fptype s1 = f[ 0 ] * ip[ 0 ]; - fptype s2 = f[ 0 ] * ip[ 1 ]; - fptype s3 = f[ 0 ] * ip[ 2 ]; - ip1 = ip; - ip2 = ip; - - for( i = 1; i < flen; i++ ) - { - ip1 += 3; - ip2 -= 3; - s1 += f[ i ] * ( ip1[ 0 ] + ip2[ 0 ]); - s2 += f[ i ] * ( ip1[ 1 ] + ip2[ 1 ]); - s3 += f[ i ] * ( ip1[ 2 ] + ip2[ 2 ]); - } - - Dst[ 0 ] = s1; - Dst[ 1 ] = s2; - Dst[ 2 ] = s3; - Dst += DstIncr; - ip += ipstep; - l--; - } - } - else - if( ElCount == 2 ) - { - while( l > 0 ) - { - fptype s1 = f[ 0 ] * ip[ 0 ]; - fptype s2 = f[ 0 ] * ip[ 1 ]; - ip1 = ip; - ip2 = ip; - - for( i = 1; i < flen; i++ ) - { - ip1 += 2; - ip2 -= 2; - s1 += f[ i ] * ( ip1[ 0 ] + ip2[ 0 ]); - s2 += f[ i ] * ( ip1[ 1 ] + ip2[ 1 ]); - } - - Dst[ 0 ] = s1; - Dst[ 1 ] = s2; - Dst += DstIncr; - ip += ipstep; - l--; - } - } - } - - /** - * Function performs resizing of a single scanline. This function does - * not "know" about the length of the source scanline buffer. This buffer - * should be padded with enough pixels so that ( SrcPos - FilterLenD2 ) is - * always >= 0 and ( SrcPos + ( DstLineLen - 1 ) * k + FilterLenD2 + 1 ) - * does not exceed source scanline's buffer length. SrcLine's increment is - * assumed to be equal to ElCount. - * - * @param SrcLine Source scanline buffer. - * @param DstLine Destination (resized) scanline buffer. - * @param DstLineIncr Destination scanline position increment, used for - * horizontal or vertical scanline stepping. - * @param xx Temporary buffer, of size FltBank -> getFilterLen(), must be - * aligned by fpclass :: fpalign. - */ - - void doResize( const fptype* SrcLine, fptype* DstLine, - const int DstLineIncr, fptype* const ) const - { - const int IntFltLen = FltBank -> getFilterLen(); - const int ElCount = Vars -> ElCount; - const typename CImageResizerFilterStep< fptype, fptypeatom > :: - CResizePos* rpos = &(*RPosBuf)[ 0 ]; - - const typename CImageResizerFilterStep< fptype, fptypeatom > :: - CResizePos* const rpose = rpos + OutLen; - -#define AVIR_RESIZE_PART1 \ - while( rpos < rpose ) \ - { \ - const fptype x = (fptype) rpos -> x; \ - const fptype* const ftp = rpos -> ftp; \ - const fptype* const ftp2 = ftp + IntFltLen; \ - const fptype* Src = SrcLine + rpos -> SrcOffs; \ - int i; - -#define AVIR_RESIZE_PART1nx \ - while( rpos < rpose ) \ - { \ - const fptype* const ftp = rpos -> ftp; \ - const fptype* Src = SrcLine + rpos -> SrcOffs; \ - int i; - -#define AVIR_RESIZE_PART2 \ - DstLine += DstLineIncr; \ - rpos++; \ - } - - if( FltBank -> getOrder() == 1 ) - { - if( ElCount == 1 ) - { - AVIR_RESIZE_PART1 - - fptype sum = 0.0; - - for( i = 0; i < IntFltLen; i++ ) - { - sum += ( ftp[ i ] + ftp2[ i ] * x ) * Src[ i ]; - } - - DstLine[ 0 ] = sum; - - AVIR_RESIZE_PART2 - } - else - if( ElCount == 4 ) - { - AVIR_RESIZE_PART1 - - fptype sum[ 4 ]; - sum[ 0 ] = 0.0; - sum[ 1 ] = 0.0; - sum[ 2 ] = 0.0; - sum[ 3 ] = 0.0; - - for( i = 0; i < IntFltLen; i++ ) - { - const fptype xx = ftp[ i ] + ftp2[ i ] * x; - sum[ 0 ] += xx * Src[ 0 ]; - sum[ 1 ] += xx * Src[ 1 ]; - sum[ 2 ] += xx * Src[ 2 ]; - sum[ 3 ] += xx * Src[ 3 ]; - Src += 4; - } - - DstLine[ 0 ] = sum[ 0 ]; - DstLine[ 1 ] = sum[ 1 ]; - DstLine[ 2 ] = sum[ 2 ]; - DstLine[ 3 ] = sum[ 3 ]; - - AVIR_RESIZE_PART2 - } - else - if( ElCount == 3 ) - { - AVIR_RESIZE_PART1 - - fptype sum[ 3 ]; - sum[ 0 ] = 0.0; - sum[ 1 ] = 0.0; - sum[ 2 ] = 0.0; - - for( i = 0; i < IntFltLen; i++ ) - { - const fptype xx = ftp[ i ] + ftp2[ i ] * x; - sum[ 0 ] += xx * Src[ 0 ]; - sum[ 1 ] += xx * Src[ 1 ]; - sum[ 2 ] += xx * Src[ 2 ]; - Src += 3; - } - - DstLine[ 0 ] = sum[ 0 ]; - DstLine[ 1 ] = sum[ 1 ]; - DstLine[ 2 ] = sum[ 2 ]; - - AVIR_RESIZE_PART2 - } - else - if( ElCount == 2 ) - { - AVIR_RESIZE_PART1 - - fptype sum[ 2 ]; - sum[ 0 ] = 0.0; - sum[ 1 ] = 0.0; - - for( i = 0; i < IntFltLen; i++ ) - { - const fptype xx = ftp[ i ] + ftp2[ i ] * x; - sum[ 0 ] += xx * Src[ 0 ]; - sum[ 1 ] += xx * Src[ 1 ]; - Src += 2; - } - - DstLine[ 0 ] = sum[ 0 ]; - DstLine[ 1 ] = sum[ 1 ]; - - AVIR_RESIZE_PART2 - } - } - else - { - if( ElCount == 1 ) - { - AVIR_RESIZE_PART1nx - - fptype sum = 0.0; - - for( i = 0; i < IntFltLen; i++ ) - { - sum += ftp[ i ] * Src[ i ]; - } - - DstLine[ 0 ] = sum; - - AVIR_RESIZE_PART2 - } - else - if( ElCount == 4 ) - { - AVIR_RESIZE_PART1nx - - fptype sum[ 4 ]; - sum[ 0 ] = 0.0; - sum[ 1 ] = 0.0; - sum[ 2 ] = 0.0; - sum[ 3 ] = 0.0; - - for( i = 0; i < IntFltLen; i++ ) - { - const fptype xx = ftp[ i ]; - sum[ 0 ] += xx * Src[ 0 ]; - sum[ 1 ] += xx * Src[ 1 ]; - sum[ 2 ] += xx * Src[ 2 ]; - sum[ 3 ] += xx * Src[ 3 ]; - Src += 4; - } - - DstLine[ 0 ] = sum[ 0 ]; - DstLine[ 1 ] = sum[ 1 ]; - DstLine[ 2 ] = sum[ 2 ]; - DstLine[ 3 ] = sum[ 3 ]; - - AVIR_RESIZE_PART2 - } - else - if( ElCount == 3 ) - { - AVIR_RESIZE_PART1nx - - fptype sum[ 3 ]; - sum[ 0 ] = 0.0; - sum[ 1 ] = 0.0; - sum[ 2 ] = 0.0; - - for( i = 0; i < IntFltLen; i++ ) - { - const fptype xx = ftp[ i ]; - sum[ 0 ] += xx * Src[ 0 ]; - sum[ 1 ] += xx * Src[ 1 ]; - sum[ 2 ] += xx * Src[ 2 ]; - Src += 3; - } - - DstLine[ 0 ] = sum[ 0 ]; - DstLine[ 1 ] = sum[ 1 ]; - DstLine[ 2 ] = sum[ 2 ]; - - AVIR_RESIZE_PART2 - } - else - if( ElCount == 2 ) - { - AVIR_RESIZE_PART1nx - - fptype sum[ 2 ]; - sum[ 0 ] = 0.0; - sum[ 1 ] = 0.0; - - for( i = 0; i < IntFltLen; i++ ) - { - const fptype xx = ftp[ i ]; - sum[ 0 ] += xx * Src[ 0 ]; - sum[ 1 ] += xx * Src[ 1 ]; - Src += 2; - } - - DstLine[ 0 ] = sum[ 0 ]; - DstLine[ 1 ] = sum[ 1 ]; - - AVIR_RESIZE_PART2 - } - } - } -#undef AVIR_RESIZE_PART2 -#undef AVIR_RESIZE_PART1nx -#undef AVIR_RESIZE_PART1 -}; - -/** - * @brief Image resizer's default dithering class. - * - * This class defines an object that performs rounding, clipping and dithering - * operations over horizontal scanline pixels before scanline is stored in the - * output buffer. - * - * The ditherer should expect the same storage order of the pixels in a - * scanline as used in the "filtering step" class. So, a separate ditherer - * class should be defined for each scanline pixel storage style. The default - * ditherer implements a simple rounding without dithering: it can be used for - * an efficient dithering method which can be multi-threaded. - * - * @tparam fptype Floating point type to use for storing pixel data. SIMD - * types can be used. - */ - -template< class fptype > -class CImageResizerDithererDefINL -{ -public: - /** - * Function initializes the ditherer object. - * - * @param aLen Scanline length in pixels to process. - * @param aVars Image resizing-related variables. - * @param aTrMul Bit-depth truncation multiplier. 1 - no additional - * truncation. - * @param aPkOut Peak output value allowed. - */ - - void init( const int aLen, const CImageResizerVars& aVars, - const double aTrMul, const double aPkOut ) - { - Len = aLen; - Vars = &aVars; - LenE = aLen * Vars -> ElCount; - TrMul0 = aTrMul; - PkOut0 = aPkOut; - } - - /** - * @return "True" if dithering is recursive relative to scanlines meaning - * multi-threaded execution is not supported by this dithering method. - */ - - static bool isRecursive() - { - return( false ); - } - - /** - * Function performs rounding and clipping operations. - * - * @param ResScanline The buffer containing the final scanline. - */ - - void dither( fptype* const ResScanline ) const - { - const fptype c0 = 0.0; - const fptype PkOut = (fptype) PkOut0; - int j; - - if( TrMul0 == 1.0 ) - { - // Optimization - do not perform bit depth truncation. - - for( j = 0; j < LenE; j++ ) - { - ResScanline[ j ] = clamp( round( ResScanline[ j ]), c0, - PkOut ); - } - } - else - { - const fptype TrMul = (fptype) TrMul0; - - for( j = 0; j < LenE; j++ ) - { - const fptype z0 = round( ResScanline[ j ] / TrMul ) * TrMul; - ResScanline[ j ] = clamp( z0, c0, PkOut ); - } - } - } - -protected: - int Len; ///< Scanline's length in pixels. - ///< - const CImageResizerVars* Vars; ///< Image resizing-related variables. - ///< - int LenE; ///< = LenE * ElCount. - ///< - double TrMul0; ///< Bit-depth truncation multiplier. - ///< - double PkOut0; ///< Peak output value allowed. - ///< -}; - -/** - * @brief Image resizer's error-diffusion dithering class, interleaved mode. - * - * This ditherer implements error-diffusion dithering which looks good, and - * whose results are compressed by PNG well. This implementation uses - * weighting coefficients obtained via machine optimization and visual - * evaluation. - * - * @tparam fptype Floating point type to use for storing pixel data. SIMD - * types can be used. - */ - -template< class fptype > -class CImageResizerDithererErrdINL : - public CImageResizerDithererDefINL< fptype > -{ -public: - /** - * Function initializes the ditherer object. - * - * @param aLen Scanline length in pixels to process. - * @param aVars Image resizing-related variables. - * @param aTrMul Bit-depth truncation multiplier. 1 - no additional - * truncation. - * @param aPkOut Peak output value allowed. - */ - - void init( const int aLen, const CImageResizerVars& aVars, - const double aTrMul, const double aPkOut ) - { - CImageResizerDithererDefINL< fptype > :: init( aLen, aVars, aTrMul, - aPkOut ); - - ResScanlineDith0.alloc( LenE + Vars -> ElCount, sizeof( fptype )); - ResScanlineDith = ResScanlineDith0 + Vars -> ElCount; - int i; - - for( i = 0; i < LenE + Vars -> ElCount; i++ ) - { - ResScanlineDith0[ i ] = 0.0; - } - } - - static bool isRecursive() - { - return( true ); - } - - void dither( fptype* const ResScanline ) - { - const int ElCount = Vars -> ElCount; - const fptype c0 = 0.0; - const fptype TrMul = (fptype) TrMul0; - const fptype PkOut = (fptype) PkOut0; - int j; - - for( j = 0; j < LenE; j++ ) - { - ResScanline[ j ] += ResScanlineDith[ j ]; - ResScanlineDith[ j ] = 0.0; - } - - for( j = 0; j < LenE - ElCount; j++ ) - { - // Perform rounding, noise estimation and saturation. - - const fptype z0 = round( ResScanline[ j ] / TrMul ) * TrMul; - const fptype Noise = ResScanline[ j ] - z0; - ResScanline[ j ] = clamp( z0, c0, PkOut ); - - ResScanline[ j + ElCount ] += Noise * (fptype) 0.364842; - ResScanlineDith[ j - ElCount ] += Noise * (fptype) 0.207305; - ResScanlineDith[ j ] += Noise * (fptype) 0.364842; - ResScanlineDith[ j + ElCount ] += Noise * (fptype) 0.063011; - } - - while( j < LenE ) - { - const fptype z0 = round( ResScanline[ j ] / TrMul ) * TrMul; - const fptype Noise = ResScanline[ j ] - z0; - ResScanline[ j ] = clamp( z0, c0, PkOut ); - - ResScanlineDith[ j - ElCount ] += Noise * (fptype) 0.207305; - ResScanlineDith[ j ] += Noise * (fptype) 0.364842; - j++; - } - } - -protected: - using CImageResizerDithererDefINL< fptype > :: Len; - using CImageResizerDithererDefINL< fptype > :: Vars; - using CImageResizerDithererDefINL< fptype > :: LenE; - using CImageResizerDithererDefINL< fptype > :: TrMul0; - using CImageResizerDithererDefINL< fptype > :: PkOut0; - - CBuffer< fptype > ResScanlineDith0; ///< Error diffusion buffer. - ///< - fptype* ResScanlineDith; ///< Error diffusion buffer pointer which skips - ///< the first ElCount elements. - ///< -}; - -/** - * @brief Floating-point processing definition and abstraction class. - * - * This class defines several constants and typedefs that point to classes - * that should be used by the image resizing algorithm. Such "definition - * class" can be used to define alternative scanline processing algorithms - * (e.g. SIMD) and image scanline packing styles used during processing. This - * class also offers an abstraction layer for dithering, rounding and - * clamping (saturation) operation. - * - * The fpclass_def class can be used to define processing using both SIMD and - * non-SIMD types, but using algorithms that are operate on interleaved pixels - * and non-SIMD optimized themselves. - * - * @tparam afptype Floating point type to use for storing intermediate data - * and variables. For variables that are not used in intensive calculations - * the "double" type is always used. On the latest Intel processors (like - * i7-4770K) there is almost no performance difference between "double" and - * "float". Image quality differences between "double" and "float" are not - * apparent on 8-bit images. At the same time the "float" uses half amount of - * working memory the "double" type uses. SIMD types can be used. The - * functions round() and clamp() in the "avir" or other visible namespace - * should be available for the specified type. SIMD types allow to perform - * resizing of images with more than 4 channels, to be exact 4 * SIMD element - * number (e.g. 16 for float4), without modification of the image resizing - * algorithm required. - * @tparam afptypeatom The atomic type the "afptype" consists of. - * @tparam adith Ditherer class to use during processing. - */ - -template< class afptype, class afptypeatom = afptype, - class adith = CImageResizerDithererDefINL< afptype > > -class fpclass_def -{ -public: - typedef afptype fptype; ///< Floating-point type to use during processing. - ///< - typedef afptypeatom fptypeatom; ///< Atomic type "fptype" consists of. - ///< - static const int fppack = sizeof( fptype ) / sizeof( fptypeatom ); ///< - ///< The number of atomic types stored in a single "fptype" element. - ///< - static const int fpalign = sizeof( fptype ); ///< Suggested alignment size - ///< in bytes. This is not a required alignment, because image - ///< resizing algorithm cannot be made to have a strictly aligned data - ///< access at all steps (e.g. interpolation cannot perform aligned - ///< accesses). - ///< - static const int elalign = 1; ///< Length alignment of arrays of elements. - ///< This applies to filters and intermediate buffers: this constant - ///< forces filters and scanlines to have a length which is a multiple - ///< of this value, for more efficient SIMD implementation. - ///< - static const int packmode = 0; ///< 0 if interleaved packing, 1 if - ///< de-interleaved. - ///< - typedef CImageResizerFilterStepINL< fptype, fptypeatom > CFilterStep; ///< - ///< Filtering step class to use during processing. - ///< - typedef adith CDitherer; ///< Ditherer class to use during processing. - ///< -}; - -/** - * @brief Image resizer class. - * - * The object of this class can be used to resize 1-4 channel images to any - * required size. Resizing is performed by utilizing interpolated sinc - * fractional delay filters plus (if necessary) a cascade of built-in - * sinc function-based 2X upsampling or 2X downsampling stages, followed by a - * correction filtering. - * - * Object of this class can be allocated on stack. - * - * @tparam fpclass Floating-point processing definition class to use. See - * avir::fpclass_def for more details. - */ - -template< class fpclass = fpclass_def< float > > -class CImageResizer -{ -public: - /** - * Constructor initializes the resizer. - * - * @param aResBitDepth Required bit depth of resulting image (1-16). If - * integer value output is used (e.g. uint8_t), the bit depth also affects - * rounding: for example, if aResBitDepth=6 and "Tout" is uint8_t, the - * result will be rounded to 6 most significant bits (2 least significant - * bits truncated, with dithering applied). - * @param aSrcBitDepth Source image's real bit-depth. Set to 0 to use - * aResBitDepth. - * @param aParams Resizing algorithm's parameters to use. Leave out for - * default values. Can be useful when performing automatic optimization of - * parameters. - */ - - CImageResizer( const int aResBitDepth = 8, const int aSrcBitDepth = 0, - const CImageResizerParams& aParams = CImageResizerParamsDef() ) - : Params( aParams ) - , ResBitDepth( aResBitDepth ) - { - SrcBitDepth = ( aSrcBitDepth == 0 ? ResBitDepth : aSrcBitDepth ); - - initFilterBank( FixedFilterBank, 1.0, false, CFltBuffer() ); - FixedFilterBank.createAllFilters(); - } - - /** - * Function resizes image. - * - * @param SrcBuf Source image buffer. - * @param SrcWidth Source image width. - * @param SrcHeight Source image height. - * @param SrcScanlineSize Physical size of source scanline in elements - * (not bytes). If this value is below 1, SrcWidth * ElCountIO will be - * used as the physical source scanline size. - * @param[out] NewBuf Buffer to accept the resized image. Can be equal to - * SrcBuf if the size of the resized image is smaller or equal to source - * image in size. - * @param NewWidth New image width. - * @param NewHeight New image height. - * @param ElCountIO The number of elements (channels) used to store each - * source and destination pixel (1-4). - * @param k Resizing step (one output pixel corresponds to "k" input - * pixels). A downsizing factor if > 1.0; upsizing factor if <= 1.0. - * Multiply by -1 if you would like to bypass "ox" and "oy" adjustment - * which is done by default to produce a centered image. If step value - * equals 0, the step value will be chosen automatically and independently - * for horizontal and vertical resizing. - * @param[in,out] aVars Pointer to variables structure to be passed to the - * image resizing function. Can be NULL. Only variables that are - * initialized in default constructor of this structure are accepted by - * this function. These variables will not be changed by this function. - * All other variables can be modified by this function. The access to - * this object is not thread-safe, each concurrent instance of this - * function should use a separate aVars object. - * @tparam Tin Input buffer element's type. Can be uint8_t (0-255 value - * range), uint16_t (0-65535 value range), float (0.0-1.0 value range), - * double (0.0-1.0 value range). Larger integer types are treated as - * uint16_t. Signed integer types are unsupported. - * @tparam Tout Output buffer element's type. Can be uint8_t (0-255 value - * range), uint16_t (0-65535 value range), float (0.0-1.0 value range), - * double (0.0-1.0 value range). Larger integer types are treated as - * uint16_t. Signed integer types are unsupported. - */ - - template< class Tin, class Tout > - void resizeImage( const Tin* const SrcBuf, const int SrcWidth, - const int SrcHeight, int SrcScanlineSize, Tout* const NewBuf, - const int NewWidth, const int NewHeight, const int ElCountIO, - const double k, CImageResizerVars* const aVars = nullptr ) const - { - if( SrcWidth == 0 || SrcHeight == 0 ) - { - memset( NewBuf, 0, (size_t) NewWidth * NewHeight * - sizeof( Tout )); - - return; - } - else - if( NewWidth == 0 || NewHeight == 0 ) - { - return; - } - - CImageResizerVars DefVars; - CImageResizerVars& Vars = ( aVars == nullptr ? DefVars : *aVars ); - - CImageResizerThreadPool DefThreadPool; - CImageResizerThreadPool& ThreadPool = ( Vars.ThreadPool == nullptr ? - DefThreadPool : *Vars.ThreadPool ); - - // Define resizing steps, also optionally modify offsets so that - // resizing produces a "centered" image. - - double kx; - double ky; - double ox = Vars.ox; - double oy = Vars.oy; - - if( k == 0.0 ) - { - if( NewWidth > SrcWidth ) - { - kx = (double) ( SrcWidth - 1 ) / ( NewWidth - 1 ); - } - else - { - kx = (double) SrcWidth / NewWidth; - ox += ( kx - 1.0 ) * 0.5; - } - - if( NewHeight > SrcHeight ) - { - ky = (double) ( SrcHeight - 1 ) / ( NewHeight - 1 ); - } - else - { - ky = (double) SrcHeight / NewHeight; - oy += ( ky - 1.0 ) * 0.5; - } - } - else - if( k > 0.0 ) - { - kx = k; - ky = k; - - if( k > 1.0 ) - { - const double ko = ( k - 1.0 ) * 0.5; - ox += ko; - oy += ko; - } - } - else - { - kx = -k; - ky = -k; - } - - // Evaluate pre-multipliers used on the output stage. - - const bool IsInFloat = ( (Tin) 0.4 != 0 ); - const bool IsOutFloat = ( (Tout) 0.4 != 0 ); - double OutMul; // Output multiplier. - - if( Vars.UseSRGBGamma ) - { - if( IsInFloat ) - { - Vars.InGammaMult = 1.0; - } - else - { - Vars.InGammaMult = - 1.0 / ( sizeof( Tin ) == 1 ? 255.0 : 65535.0 ); - } - - if( IsOutFloat ) - { - Vars.OutGammaMult = 1.0; - } - else - { - Vars.OutGammaMult = ( sizeof( Tout ) == 1 ? 255.0 : 65535.0 ); - } - - OutMul = 1.0; - } - else - { - if( IsOutFloat ) - { - OutMul = 1.0; - } - else - { - OutMul = ( sizeof( Tout ) == 1 ? 255.0 : 65535.0 ); - } - - if( !IsInFloat ) - { - OutMul /= ( sizeof( Tin ) == 1 ? 255.0 : 65535.0 ); - } - } - - // Fill widely-used variables. - - const int ElCount = ( ElCountIO + fpclass :: fppack - 1 ) / - fpclass :: fppack; - - const int NewWidthE = NewWidth * ElCount; - - if( SrcScanlineSize < 1 ) - { - SrcScanlineSize = SrcWidth * ElCountIO; - } - - Vars.ElCount = ElCount; - Vars.ElCountIO = ElCountIO; - Vars.fppack = fpclass :: fppack; - Vars.fpalign = fpclass :: fpalign; - Vars.elalign = fpclass :: elalign; - Vars.packmode = fpclass :: packmode; - - // Horizontal scanline filtering and resizing. - - CDSPFracFilterBankLin< fptype > FltBank; - CFilterSteps FltSteps; - typename CFilterStep :: CRPosBufArray RPosBufArray; - CBuffer< uint8_t > UsedFracMap; - - // Perform the filtering steps modeling at various modes, find the - // most efficient mode for both horizontal and vertical resizing. - - int UseBuildMode = 1; - const int BuildModeCount = - ( FixedFilterBank.getOrder() == 0 ? 4 : 2 ); - - int m; - - if( Vars.BuildMode >= 0 ) - { - UseBuildMode = Vars.BuildMode; - } - else - { - int BestScore = 0x7FFFFFFF; - - for( m = 0; m < BuildModeCount; m++ ) - { - CDSPFracFilterBankLin< fptype > TmpBank; - CFilterSteps TmpSteps; - Vars.k = kx; - Vars.o = ox; - buildFilterSteps( TmpSteps, Vars, TmpBank, OutMul, m, true ); - updateFilterStepBuffers( TmpSteps, Vars, RPosBufArray, - SrcWidth, NewWidth ); - - fillUsedFracMap( TmpSteps[ Vars.ResizeStep ], UsedFracMap ); - const int c = calcComplexity( TmpSteps, Vars, UsedFracMap, - SrcHeight ); - - if( c < BestScore ) - { - UseBuildMode = m; - BestScore = c; - } - } - } - - // Perform the actual filtering steps building. - - Vars.k = kx; - Vars.o = ox; - buildFilterSteps( FltSteps, Vars, FltBank, OutMul, UseBuildMode, - false ); - - updateFilterStepBuffers( FltSteps, Vars, RPosBufArray, SrcWidth, - NewWidth ); - - updateBufLenAndRPosPtrs( FltSteps, Vars, NewWidth ); - - const int ThreadCount = ThreadPool.getSuggestedWorkloadCount(); - // Includes the current thread. - - CStructArray< CThreadData< Tin, Tout > > td; - td.setItemCount( ThreadCount ); - int i; - - for( i = 0; i < ThreadCount; i++ ) - { - if( i > 0 ) - { - ThreadPool.addWorkload( &td[ i ]); - } - - td[ i ].init( i, ThreadCount, FltSteps, Vars ); - - td[ i ].initScanlineQueue( td[ i ].sopResizeH, SrcHeight, - SrcWidth ); - } - - CBuffer< fptype, size_t > FltBuf( (size_t) NewWidthE * SrcHeight, - fpclass :: fpalign ); // Temporary buffer that receives - // horizontally-filtered and resized image. - - for( i = 0; i < SrcHeight; i++ ) - { - td[ i % ThreadCount ].addScanlineToQueue( - (void*) &SrcBuf[ (size_t) i * SrcScanlineSize ], - &FltBuf[ (size_t) i * NewWidthE ]); - } - - ThreadPool.startAllWorkloads(); - td[ 0 ].processScanlineQueue(); - ThreadPool.waitAllWorkloadsToFinish(); - - // Vertical scanline filtering and resizing, reuse previously defined - // filtering steps if possible. - - const int PrevUseBuildMode = UseBuildMode; - - if( Vars.BuildMode >= 0 ) - { - UseBuildMode = Vars.BuildMode; - } - else - { - CImageResizerVars TmpVars( Vars ); - int BestScore = 0x7FFFFFFF; - - for( m = 0; m < BuildModeCount; m++ ) - { - CDSPFracFilterBankLin< fptype > TmpBank; - TmpBank.copyInitParams( FltBank ); - CFilterSteps TmpSteps; - TmpVars.k = ky; - TmpVars.o = oy; - buildFilterSteps( TmpSteps, TmpVars, TmpBank, 1.0, m, true ); - updateFilterStepBuffers( TmpSteps, TmpVars, RPosBufArray, - SrcHeight, NewHeight ); - - fillUsedFracMap( TmpSteps[ TmpVars.ResizeStep ], - UsedFracMap ); - - const int c = calcComplexity( TmpSteps, TmpVars, UsedFracMap, - NewWidth ); - - if( c < BestScore ) - { - UseBuildMode = m; - BestScore = c; - } - } - } - - Vars.k = ky; - Vars.o = oy; - - if( UseBuildMode == PrevUseBuildMode && ky == kx ) - { - if( OutMul != 1.0 ) - { - modifyCorrFilterDCGain( FltSteps, 1.0 / OutMul ); - } - } - else - { - buildFilterSteps( FltSteps, Vars, FltBank, 1.0, UseBuildMode, - false ); - } - - updateFilterStepBuffers( FltSteps, Vars, RPosBufArray, SrcHeight, - NewHeight ); - - updateBufLenAndRPosPtrs( FltSteps, Vars, NewWidth ); - - if( IsOutFloat && sizeof( FltBuf[ 0 ]) == sizeof( Tout ) && - fpclass :: packmode == 0 ) - { - // In-place output. - - for( i = 0; i < ThreadCount; i++ ) - { - td[ i ].initScanlineQueue( td[ i ].sopResizeV, NewWidth, - SrcHeight, NewWidthE, NewWidthE ); - } - - for( i = 0; i < NewWidth; i++ ) - { - td[ i % ThreadCount ].addScanlineToQueue( - &FltBuf[ (size_t) i * ElCount ], - (fptype*) (void*) &NewBuf[ (size_t) i * ElCount ]); - } - - ThreadPool.startAllWorkloads(); - td[ 0 ].processScanlineQueue(); - ThreadPool.waitAllWorkloadsToFinish(); - ThreadPool.removeAllWorkloads(); - - return; - } - - CBuffer< fptype, size_t > ResBuf( (size_t) NewWidthE * NewHeight, - fpclass :: fpalign ); - - for( i = 0; i < ThreadCount; i++ ) - { - td[ i ].initScanlineQueue( td[ i ].sopResizeV, NewWidth, - SrcHeight, NewWidthE, NewWidthE ); - } - - const int im = ( fpclass :: packmode == 0 ? ElCount : 1 ); - - for( i = 0; i < NewWidth; i++ ) - { - td[ i % ThreadCount ].addScanlineToQueue( - &FltBuf[ (size_t) i * im ], &ResBuf[ (size_t) i * im ]); - } - - ThreadPool.startAllWorkloads(); - td[ 0 ].processScanlineQueue(); - ThreadPool.waitAllWorkloadsToFinish(); - - if( IsOutFloat ) - { - // Perform output, but skip dithering. - - for( i = 0; i < ThreadCount; i++ ) - { - td[ i ].initScanlineQueue( td[ i ].sopUnpackH, - NewHeight, NewWidth ); - } - - for( i = 0; i < NewHeight; i++ ) - { - td[ i % ThreadCount ].addScanlineToQueue( - &ResBuf[ (size_t) i * NewWidthE ], - &NewBuf[ (size_t) i * NewWidth * ElCountIO ]); - } - - ThreadPool.startAllWorkloads(); - td[ 0 ].processScanlineQueue(); - ThreadPool.waitAllWorkloadsToFinish(); - ThreadPool.removeAllWorkloads(); - - return; - } - - // Perform output with dithering (for integer output only). - - int TruncBits; // The number of lower bits to truncate and dither. - int OutRange; // Output range. - - if( sizeof( Tout ) == 1 ) - { - TruncBits = 8 - ResBitDepth; - OutRange = 255; - } - else - { - TruncBits = 16 - ResBitDepth; - OutRange = 65535; - } - - const double PkOut = OutRange; - const double TrMul = ( TruncBits > 0 ? - PkOut / ( OutRange >> TruncBits ) : 1.0 ); - - if( CDitherer :: isRecursive() ) - { - td[ 0 ].getDitherer().init( NewWidth, Vars, TrMul, PkOut ); - - if( Vars.UseSRGBGamma ) - { - for( i = 0; i < NewHeight; i++ ) - { - fptype* const ResScanline = - &ResBuf[ (size_t) i * NewWidthE ]; - - CFilterStep :: applySRGBGamma( ResScanline, NewWidth, - Vars ); - - td[ 0 ].getDitherer().dither( ResScanline ); - - CFilterStep :: unpackScanline( ResScanline, - &NewBuf[ (size_t) i * NewWidth * ElCountIO ], - NewWidth, Vars ); - } - } - else - { - for( i = 0; i < NewHeight; i++ ) - { - fptype* const ResScanline = - &ResBuf[ (size_t) i * NewWidthE ]; - - td[ 0 ].getDitherer().dither( ResScanline ); - - CFilterStep :: unpackScanline( ResScanline, - &NewBuf[ (size_t) i * NewWidth * ElCountIO ], - NewWidth, Vars ); - } - } - } - else - { - for( i = 0; i < ThreadCount; i++ ) - { - td[ i ].initScanlineQueue( td[ i ].sopDitherAndUnpackH, - NewHeight, NewWidth ); - - td[ i ].getDitherer().init( NewWidth, Vars, TrMul, PkOut ); - } - - for( i = 0; i < NewHeight; i++ ) - { - td[ i % ThreadCount ].addScanlineToQueue( - &ResBuf[ (size_t) i * NewWidthE ], - &NewBuf[ (size_t) i * NewWidth * ElCountIO ]); - } - - ThreadPool.startAllWorkloads(); - td[ 0 ].processScanlineQueue(); - ThreadPool.waitAllWorkloadsToFinish(); - } - - ThreadPool.removeAllWorkloads(); - } - -private: - typedef typename fpclass :: fptype fptype; ///< Floating-point type to use - ///< during processing. - ///< - typedef typename fpclass :: CFilterStep CFilterStep; ///< Filtering step - ///< class to use during processing. - ///< - typedef typename fpclass :: CDitherer CDitherer; ///< Ditherer class to - ///< use during processing. - ///< - CImageResizerParams Params; ///< Algorithm's parameters currently in use. - ///< - int SrcBitDepth; ///< Bit resolution of the source image. - ///< - int ResBitDepth; ///< Bit resolution of the resulting image. - ///< - CDSPFracFilterBankLin< fptype > FixedFilterBank; ///< Fractional delay - ///< filter bank with fixed characteristics, mainly for upsizing - ///< cases. - ///< - - /** - * @brief Filtering steps array. - * - * The object of this class stores filtering steps together. - */ - - typedef CStructArray< CFilterStep > CFilterSteps; - - /** - * Function initializes the filter bank in the specified resizing step - * according to the source and resulting image bit depths. - * - * @param FltBank Filter bank to initialize. - * @param CutoffMult Cutoff multiplier, 0 to 1. 1 corresponds to 0.5pi - * cutoff point. - * @param ForceHiOrder "True" if a high-order interpolation should be - * forced which requires considerably less resources for initialization. - * @param ExtFilter External filter to apply to interpolation filter. - */ - - void initFilterBank( CDSPFracFilterBankLin< fptype >& FltBank, - const double CutoffMult, const bool ForceHiOrder, - const CFltBuffer& ExtFilter ) const - { - const int IntBitDepth = ( ResBitDepth > SrcBitDepth ? ResBitDepth : - SrcBitDepth ); - - const double SNR = -6.02 * ( IntBitDepth + 3 ); - int UseOrder; - int FracCount; // The number of fractional delay filters sampled by - // the filter bank. This variable affects the signal-to-noise - // ratio at interpolation stage. Theoretically, at UseOrder==1, - // 8-bit image resizing requires 66.2 dB SNR or 11. 16-bit - // resizing requires 114.4 dB SNR or 150. At UseOrder=0 the - // required number of filters is exponentially higher. - - if( ForceHiOrder || IntBitDepth > 8 ) - { - UseOrder = 1; // -146 dB max - FracCount = (int) ceil( 0.23134052 * exp( -0.058062929 * SNR )); - } - else - { - UseOrder = 0; // -72 dB max - FracCount = (int) ceil( 0.33287686 * exp( -0.11334583 * SNR )); - } - - if( FracCount < 2 ) - { - FracCount = 2; - } - - FltBank.init( FracCount, UseOrder, Params.IntFltLen / CutoffMult, - Params.IntFltCutoff * CutoffMult, Params.IntFltAlpha, ExtFilter, - fpclass :: fpalign, fpclass :: elalign ); - } - - /** - * Function allocates filter buffer taking "fpclass" alignments into - * account. The allocated buffer may be larger than the requested size: in - * this case the additional elements will be zeroed by this function. - * - * @param Flt Filter buffer. - * @param ReqCapacity The required filter buffer's capacity. - * @param IsModel "True" if filtering steps modeling is performed without - * actual filter allocation. - * @param FltExt If non-NULL this variable will receive the number of - * elements the filter was extended by. - */ - - static void allocFilter( CBuffer< fptype >& Flt, const int ReqCapacity, - const bool IsModel = false, int* const FltExt = nullptr ) - { - int UseCapacity = ( ReqCapacity + fpclass :: elalign - 1 ) & - ~( fpclass :: elalign - 1 ); - - int Ext = UseCapacity - ReqCapacity; - - if( FltExt != nullptr ) - { - *FltExt = Ext; - } - - if( IsModel ) - { - Flt.forceCapacity( UseCapacity ); - return; - } - - Flt.alloc( UseCapacity, fpclass :: fpalign ); - - while( Ext > 0 ) - { - Ext--; - Flt[ ReqCapacity + Ext ] = 0.0; - } - } - - /** - * Function assigns filter parameters to the specified filtering step - * object. - * - * @param fs Filtering step to assign parameter to. This step cannot be - * the last step if ResampleFactor greater than 1 was specified. - * @param IsUpsample "True" if upsampling step. Should be set to "false" - * if FltCutoff is negative. - * @param ResampleFactor Resampling factor of this filter (>=1). - * @param FltCutoff Filter cutoff point. This value will be divided by the - * ResampleFactor if IsUpsample equals "true". If zero value was - * specified, the "half-band" predefined filter will be created. In this - * case the ResampleFactor will modify the filter cutoff point. - * @param DCGain DC gain to apply to the filter. Assigned to filtering - * step's DCGain variable. - * @param UseFltOrig "True" if the originally-designed filter should be - * left in filtering step's FltOrig buffer. Otherwise it will be freed. - * @param IsModel "True" if filtering steps modeling is performed without - * actual filter building. - */ - - void assignFilterParams( CFilterStep& fs, const bool IsUpsample, - const int ResampleFactor, const double FltCutoff, const double DCGain, - const bool UseFltOrig, const bool IsModel ) const - { - double FltAlpha; - double Len2; - double Freq; - - if( FltCutoff == 0.0 ) - { - const double m = 2.0 / ResampleFactor; - FltAlpha = Params.HBFltAlpha; - Len2 = 0.5 * Params.HBFltLen / m; - Freq = AVIR_PI * Params.HBFltCutoff * m; - } - else - { - FltAlpha = Params.LPFltAlpha; - Len2 = 0.25 * Params.LPFltBaseLen / FltCutoff; - Freq = AVIR_PI * Params.LPFltCutoffMult * FltCutoff; - } - - if( IsUpsample ) - { - Len2 *= ResampleFactor; - Freq /= ResampleFactor; - fs.DCGain = DCGain * ResampleFactor; - } - else - { - fs.DCGain = DCGain; - } - - fs.FltOrig.Len2 = Len2; - fs.FltOrig.Freq = Freq; - fs.FltOrig.Alpha = FltAlpha; - fs.FltOrig.DCGain = fs.DCGain; - - CDSPPeakedCosineLPF w( Len2, Freq, FltAlpha ); - - fs.IsUpsample = IsUpsample; - fs.ResampleFactor = ResampleFactor; - fs.FltLatency = w.fl2; - - int FltExt; // Filter's extension due to fpclass :: elalign. - - if( IsModel ) - { - allocFilter( fs.Flt, w.FilterLen, true, &FltExt ); - - if( UseFltOrig ) - { - // Allocate a real buffer even in modeling mode since this - // filter may be copied by the filter bank. - - fs.FltOrig.alloc( w.FilterLen ); - memset( &fs.FltOrig[ 0 ], 0, - w.FilterLen * sizeof( fs.FltOrig[ 0 ])); - } - } - else - { - fs.FltOrig.alloc( w.FilterLen ); - - w.generateLPF( &fs.FltOrig[ 0 ], 1.0 ); - optimizeFIRFilter( fs.FltOrig, fs.FltLatency ); - normalizeFIRFilter( &fs.FltOrig[ 0 ], fs.FltOrig.getCapacity(), - fs.DCGain ); - - allocFilter( fs.Flt, fs.FltOrig.getCapacity(), false, &FltExt ); - copyArray( &fs.FltOrig[ 0 ], &fs.Flt[ 0 ], - fs.FltOrig.getCapacity() ); - - if( !UseFltOrig ) - { - fs.FltOrig.free(); - } - } - - if( IsUpsample ) - { - int l = fs.Flt.getCapacity() - fs.FltLatency - ResampleFactor - - FltExt; - - allocFilter( fs.PrefixDC, l, IsModel ); - allocFilter( fs.SuffixDC, fs.FltLatency, IsModel ); - - if( IsModel ) - { - return; - } - - // Create prefix and suffix "tails" used during upsampling. - - const fptype* ip = &fs.Flt[ fs.FltLatency + ResampleFactor ]; - copyArray( ip, &fs.PrefixDC[ 0 ], l ); - - while( true ) - { - ip += ResampleFactor; - l -= ResampleFactor; - - if( l <= 0 ) - { - break; - } - - addArray( ip, &fs.PrefixDC[ 0 ], l ); - } - - l = fs.FltLatency; - fptype* op = &fs.SuffixDC[ 0 ]; - copyArray( &fs.Flt[ 0 ], op, l ); - - while( true ) - { - op += ResampleFactor; - l -= ResampleFactor; - - if( l <= 0 ) - { - break; - } - - addArray( &fs.Flt[ 0 ], op, l ); - } - } - else - if( !UseFltOrig ) - { - fs.EdgePixelCount = fs.EdgePixelCountDef; - } - } - - /** - * Function adds a correction filter that tries to achieve a linear - * frequency response at all frequencies. The actual resulting response - * may feature a slight damping of the highest frequencies since a - * suitably short correction filter cannot fix steep high-frequency - * damping. - * - * This function assumes that the resizing step is currently the last - * step, even if it was not inserted yet: this allows placement of the - * correction filter both before and after the resizing step. - * - * @param Steps Filtering steps. - * @param bw Resulting bandwidth relative to the original bandwidth (which - * is 1.0), usually 1/k. Should be <= 1.0. - * @param IsPreCorrection "True" if the filtering step was already created - * and it is first in the Steps array. "True" also adds edge pixels to - * reduce edge artifacts. - * @param IsModel "True" if filtering steps modeling is performed without - * actual filter building. - */ - - void addCorrectionFilter( CFilterSteps& Steps, const double bw, - const bool IsPreCorrection, const bool IsModel ) const - { - CFilterStep& fs = ( IsPreCorrection ? Steps[ 0 ] : Steps.add() ); - fs.IsUpsample = false; - fs.ResampleFactor = 1; - fs.DCGain = 1.0; - fs.EdgePixelCount = ( IsPreCorrection ? fs.EdgePixelCountDef : 0 ); - - if( IsModel ) - { - allocFilter( fs.Flt, CDSPFIREQ :: calcFilterLength( - Params.CorrFltLen, fs.FltLatency ), true ); - - return; - } - - const int BinCount = 65; // Frequency response bins to control. - const int BinCount1 = BinCount - 1; - double curbw = 1.0; // Bandwidth of the filter at the current step. - int i; - int j; - double re; - double im; - - CBuffer< double > Bins( BinCount ); // Adjustment introduced by all - // steps at all frequencies of interest. - - for( j = 0; j < BinCount; j++ ) - { - Bins[ j ] = 1.0; - } - - const int si = ( IsPreCorrection ? 1 : 0 ); - - for( i = si; i < Steps.getItemCount() - ( si ^ 1 ); i++ ) - { - const CFilterStep& fs = Steps[ i ]; - - if( fs.IsUpsample ) - { - curbw *= fs.ResampleFactor; - - if( fs.FltOrig.getCapacity() > 0 ) - { - continue; - } - } - - const double dcg = 1.0 / fs.DCGain; // DC gain correction. - const fptype* Flt; - int FltLen; - - if( fs.ResampleFactor == 0 ) - { - Flt = fs.FltBank -> getFilter( 0 ); - FltLen = fs.FltBank -> getFilterLen(); - } - else - { - Flt = &fs.Flt[ 0 ]; - FltLen = fs.Flt.getCapacity(); - } - - // Calculate frequency response adjustment introduced by the - // filter at this step, within the bounds of bandwidth of - // interest. - - for( j = 0; j < BinCount; j++ ) - { - const double th = AVIR_PI * bw / curbw * j / BinCount1; - - calcFIRFilterResponse( Flt, FltLen, th, re, im ); - - Bins[ j ] /= sqrt( re * re + im * im ) * dcg; - } - - if( !fs.IsUpsample && fs.ResampleFactor > 1 ) - { - curbw /= fs.ResampleFactor; - } - } - - // Calculate filter. - - CDSPFIREQ EQ; - EQ.init( bw * 2.0, Params.CorrFltLen, BinCount, 0.0, bw, false, - Params.CorrFltAlpha ); - - fs.FltLatency = EQ.getFilterLatency(); - - CBuffer< double > Filter( EQ.getFilterLength() ); - EQ.buildFilter( Bins, &Filter[ 0 ]); - normalizeFIRFilter( &Filter[ 0 ], Filter.getCapacity(), 1.0 ); - optimizeFIRFilter( Filter, fs.FltLatency ); - normalizeFIRFilter( &Filter[ 0 ], Filter.getCapacity(), 1.0 ); - - allocFilter( fs.Flt, Filter.getCapacity() ); - copyArray( &Filter[ 0 ], &fs.Flt[ 0 ], Filter.getCapacity() ); - - // Print a theoretically achieved final frequency response at various - // feature sizes (from DC to 1 pixel). Values above 255 means features - // become brighter, values below 255 means features become dimmer. - -/* const double sbw = ( bw > 1.0 ? 1.0 / bw : 1.0 ); - - for( j = 0; j < BinCount; j++ ) - { - const double th = AVIR_PI * sbw * j / BinCount1; - - calcFIRFilterResponse( &fs.Flt[ 0 ], fs.Flt.getCapacity(), - th, re, im ); - - printf( "%f\n", sqrt( re * re + im * im ) / Bins[ j ] * 255 ); - } - - printf( "***\n" );*/ - } - - /** - * Function adds a sharpening filter if image is being upsized. Such - * sharpening allows to spot interpolation filter's stop-band attenuation: - * if attenuation is too weak, a "dark grid" and other artifacts may - * become visible. - * - * It is assumed that 40 decibel stop-band attenuation should be - * considered a required minimum: this allows application of (deliberately - * strong) 64X sharpening without spotting any artifacts. - * - * @param Steps Filtering steps. - * @param bw Resulting bandwidth relative to the original bandwidth (which - * is 1.0), usually 1/k. - * @param IsModel "True" if filtering steps modeling is performed without - * actual filter building. - */ - - static void addSharpenTest( CFilterSteps& Steps, const double bw, - const bool IsModel ) - { - if( bw <= 1.0 ) - { - return; - } - - const double FltLen = 10.0 * bw; - - CFilterStep& fs = Steps.add(); - fs.IsUpsample = false; - fs.ResampleFactor = 1; - fs.DCGain = 1.0; - fs.EdgePixelCount = 0; - - if( IsModel ) - { - allocFilter( fs.Flt, CDSPFIREQ :: calcFilterLength( FltLen, - fs.FltLatency ), true ); - - return; - } - - const int BinCount = 200; - CBuffer< double > Bins( BinCount ); - int Thresh = (int) round( BinCount / bw * 1.75 ); - - if( Thresh > BinCount ) - { - Thresh = BinCount; - } - - int j; - - for( j = 0; j < Thresh; j++ ) - { - Bins[ j ] = 1.0; - } - - for( j = Thresh; j < BinCount; j++ ) - { - Bins[ j ] = 256.0; - } - - CDSPFIREQ EQ; - EQ.init( bw * 2.0, FltLen, BinCount, 0.0, bw, false, 1.7 ); - - fs.FltLatency = EQ.getFilterLatency(); - - CBuffer< double > Filter( EQ.getFilterLength() ); - EQ.buildFilter( Bins, &Filter[ 0 ]); - normalizeFIRFilter( &Filter[ 0 ], Filter.getCapacity(), 1.0 ); - optimizeFIRFilter( Filter, fs.FltLatency ); - normalizeFIRFilter( &Filter[ 0 ], Filter.getCapacity(), 1.0 ); - - allocFilter( fs.Flt, Filter.getCapacity() ); - copyArray( &Filter[ 0 ], &fs.Flt[ 0 ], Filter.getCapacity() ); - -/* for( j = 0; j < BinCount; j++ ) - { - const double th = AVIR_PI * j / ( BinCount - 1 ); - double re; - double im; - - calcFIRFilterResponse( &fs.Flt[ 0 ], fs.Flt.getCapacity(), - th, re, im ); - - printf( "%f\n", sqrt( re * re + im * im )); - } - - printf( "***\n" );*/ - } - - /** - * Function builds sequence of filtering steps depending on the specified - * resizing coefficient. The last steps included are always the resizing - * step then (possibly) the correction step. - * - * @param Steps Array that receives filtering steps. - * @param[out] Vars Variables object. - * @param FltBank Filter bank to initialize and use. - * @param DCGain The overall DC gain to apply. This DC gain is applied to - * the first filtering step only (upsampling or filtering step). - * @param ModeFlags Build mode flags to use. This is a bitmap of switches - * that enable or disable certain algorithm features. - * @param IsModel "True" if filtering steps modeling is performed without - * the actual filter allocation and building. - */ - - void buildFilterSteps( CFilterSteps& Steps, CImageResizerVars& Vars, - CDSPFracFilterBankLin< fptype >& FltBank, const double DCGain, - const int ModeFlags, const bool IsModel ) const - { - Steps.clear(); - - const bool DoFltAndIntCombo = (( ModeFlags & 1 ) != 0 ); // Do filter - // and interpolator combining. - const bool ForceHiOrderInt = (( ModeFlags & 2 ) != 0 ); // Force use - // of a higher-order interpolation. - const bool UseHalfband = (( ModeFlags & 4 ) != 0 ); // Use half-band - // filter. - - const double bw = 1.0 / Vars.k; // Resulting bandwidth. - const int UpsampleFactor = ( (int) floor( Vars.k ) < 2 ? 2 : 1 ); - double IntCutoffMult; // Interpolation filter cutoff multiplier. - CFilterStep* ReuseStep; // If not NULL, resizing step should use - // this step object instead of creating a new one. - CFilterStep* ExtFltStep; // Use FltOrig of this step as the external - // filter to applied to the interpolator. - bool IsPreCorrection; // "True" if the correction filter is applied - // first. - double FltCutoff; // Cutoff frequency of the first filtering step. - double corrbw; ///< Bandwidth at the correction step. - - if( Vars.k <= 1.0 ) - { - IsPreCorrection = true; - FltCutoff = 1.0; - corrbw = 1.0; - Steps.add(); - } - else - { - IsPreCorrection = false; - FltCutoff = bw; - corrbw = bw; - } - - // Add 1 upsampling or several downsampling filters. - - if( UpsampleFactor > 1 ) - { - CFilterStep& fs = Steps.add(); - assignFilterParams( fs, true, UpsampleFactor, FltCutoff, DCGain, - DoFltAndIntCombo, IsModel ); - - IntCutoffMult = FltCutoff * 2.0 / UpsampleFactor; - ReuseStep = nullptr; - ExtFltStep = ( DoFltAndIntCombo ? &fs : nullptr ); - } - else - { - int DownsampleFactor; - - while( true ) - { - DownsampleFactor = (int) floor( 0.5 / FltCutoff ); - bool DoHBFltAdd; - - if( DownsampleFactor > 16 ) - { - // Add half-band filter unconditionally in order to keep - // filter lengths lower for more precise frequency - // response and less edge artifacts. - - DoHBFltAdd = true; - DownsampleFactor = 16; - } - else - { - DoHBFltAdd = ( UseHalfband && DownsampleFactor > 1 ); - } - - if( DoHBFltAdd ) - { - assignFilterParams( Steps.add(), false, DownsampleFactor, - 0.0, 1.0, false, IsModel ); - - FltCutoff *= DownsampleFactor; - } - else - { - if( DownsampleFactor < 1 ) - { - DownsampleFactor = 1; - } - - break; - } - } - - CFilterStep& fs = Steps.add(); - assignFilterParams( fs, false, DownsampleFactor, FltCutoff, - DCGain, DoFltAndIntCombo, IsModel ); - - IntCutoffMult = FltCutoff / 0.5; - - if( DoFltAndIntCombo ) - { - ReuseStep = &fs; - ExtFltStep = &fs; - } - else - { - IntCutoffMult *= DownsampleFactor; - ReuseStep = nullptr; - ExtFltStep = nullptr; - } - } - - // Insert resizing and correction steps. - - CFilterStep& fs = ( ReuseStep == nullptr ? Steps.add() : *ReuseStep ); - - Vars.ResizeStep = Steps.getItemCount() - 1; - fs.IsUpsample = false; - fs.ResampleFactor = 0; - fs.DCGain = ( ExtFltStep == nullptr ? 1.0 : ExtFltStep -> DCGain ); - - initFilterBank( FltBank, IntCutoffMult, ForceHiOrderInt, - ( ExtFltStep == nullptr ? fs.FltOrig : ExtFltStep -> FltOrig )); - - if( FltBank == FixedFilterBank ) - { - fs.FltBank = (CDSPFracFilterBankLin< fptype >*) &FixedFilterBank; - } - else - { - fs.FltBank = &FltBank; - } - - addCorrectionFilter( Steps, corrbw, IsPreCorrection, IsModel ); - - //addSharpenTest( Steps, bw, IsModel ); - } - - /** - * Function extends *this upsampling step so that it produces more - * upsampled pixels that cover the prefix and suffix needs of the next - * step. After the call to this function the InPrefix and InSuffix - * variables of the next step will be set to zero. - * - * @param fs Upsampling filtering step. - * @param NextStep The next step structure. - */ - - static void extendUpsample( CFilterStep& fs, CFilterStep& NextStep ) - { - fs.InPrefix = ( NextStep.InPrefix + fs.ResampleFactor - 1 ) / - fs.ResampleFactor; - - fs.OutPrefix += fs.InPrefix * fs.ResampleFactor; - NextStep.InPrefix = 0; - - fs.InSuffix = ( NextStep.InSuffix + fs.ResampleFactor - 1 ) / - fs.ResampleFactor; - - fs.OutSuffix += fs.InSuffix * fs.ResampleFactor; - NextStep.InSuffix = 0; - } - - /** - * Function fills resizing step's RPosBuf array, excluding the actual - * "ftp" pointers and "SrcOffs" offsets. - * - * This array should be cleared if the resizing step or offset were - * changed. Otherwise this function only fills the elements required to - * cover resizing step's OutLen. - * - * This function is called by the updateFilterStepBuffers() function. - * - * @param fs Resizing step. - * @param Vars Variables object. - */ - - static void fillRPosBuf( CFilterStep& fs, const CImageResizerVars& Vars ) - { - const int PrevLen = fs.RPosBuf -> getCapacity(); - - if( fs.OutLen > PrevLen ) - { - fs.RPosBuf -> increaseCapacity( fs.OutLen ); - } - - typename CFilterStep :: CResizePos* rpos = &(*fs.RPosBuf)[ PrevLen ]; - const int FracCount = fs.FltBank -> getFracCount(); - const double o = Vars.o; - const double k = Vars.k; - int i; - - for( i = PrevLen; i < fs.OutLen; i++ ) - { - const double SrcPos = o + k * i; - const int SrcPosInt = (int) floor( SrcPos ); - const double x = ( SrcPos - SrcPosInt ) * FracCount; - const int fti = (int) x; - rpos -> x = (typename fpclass :: fptypeatom) ( x - fti ); - rpos -> fti = fti; - rpos -> SrcPosInt = SrcPosInt; - rpos++; - } - } - - /** - * Function updates filtering step buffer lengths depending on the - * specified source and new scanline lengths. This function should be - * called after the buildFilterSteps() function. - * - * @param Steps Array that receives filtering steps. - * @param[out] Vars Variables object, will receive buffer size and length. - * This function expects "k" and "o" variable values that will be - * adjusted by this function. - * @param RPosBufArray Resizing position buffers array, used to obtain - * buffer to initialize and use (will be reused if it is already fully or - * partially filled). - * @param SrcLen Source scanline's length in pixels. - * @param NewLen New scanline's length in pixels. - */ - - static void updateFilterStepBuffers( CFilterSteps& Steps, - CImageResizerVars& Vars, - typename CFilterStep :: CRPosBufArray& RPosBufArray, int SrcLen, - const int NewLen ) - { - int upstep = -1; - int InBuf = 0; - int i; - - for( i = 0; i < Steps.getItemCount(); i++ ) - { - CFilterStep& fs = Steps[ i ]; - - fs.Vars = &Vars; - fs.InLen = SrcLen; - fs.InBuf = InBuf; - fs.OutBuf = ( InBuf + 1 ) & 1; - - if( fs.IsUpsample ) - { - upstep = i; - Vars.k *= fs.ResampleFactor; - Vars.o *= fs.ResampleFactor; - fs.InPrefix = 0; - fs.InSuffix = 0; - fs.OutLen = fs.InLen * fs.ResampleFactor; - fs.OutPrefix = fs.FltLatency; - fs.OutSuffix = fs.Flt.getCapacity() - fs.FltLatency - - fs.ResampleFactor; - - int l0 = fs.OutPrefix + fs.OutLen + fs.OutSuffix; - int l = fs.InLen * fs.ResampleFactor + - fs.SuffixDC.getCapacity(); - - if( l > l0 ) - { - fs.OutSuffix += l - l0; - } - - l0 = fs.OutLen + fs.OutSuffix; - - if( fs.PrefixDC.getCapacity() > l0 ) - { - fs.OutSuffix += fs.PrefixDC.getCapacity() - l0; - } - } - else - if( fs.ResampleFactor == 0 ) - { - const int FilterLenD2 = fs.FltBank -> getFilterLen() / 2; - const int FilterLenD21 = FilterLenD2 - 1; - - const int ResizeLPix = (int) floor( Vars.o ) - FilterLenD21; - fs.InPrefix = ( ResizeLPix < 0 ? -ResizeLPix : 0 ); - const int ResizeRPix = (int) floor( Vars.o + - ( NewLen - 1 ) * Vars.k ) + FilterLenD2 + 1; - - fs.InSuffix = ( ResizeRPix > fs.InLen ? - ResizeRPix - fs.InLen : 0 ); - - fs.OutLen = NewLen; - fs.RPosBuf = &RPosBufArray.getRPosBuf( Vars.k, Vars.o, - fs.FltBank -> getFracCount() ); - - fillRPosBuf( fs, Vars ); - } - else - { - Vars.k /= fs.ResampleFactor; - Vars.o /= fs.ResampleFactor; - Vars.o += fs.EdgePixelCount; - - fs.InPrefix = fs.FltLatency; - fs.InSuffix = fs.Flt.getCapacity() - fs.FltLatency - 1; - - // Additionally extend OutLen to produce more precise edge - // pixels. - - fs.OutLen = ( fs.InLen + fs.ResampleFactor - 1 ) / - fs.ResampleFactor + fs.EdgePixelCount; - - fs.InSuffix += ( fs.OutLen - 1 ) * fs.ResampleFactor + 1 - - fs.InLen; - - fs.InPrefix += fs.EdgePixelCount * fs.ResampleFactor; - fs.OutLen += fs.EdgePixelCount; - } - - InBuf = fs.OutBuf; - SrcLen = fs.OutLen; - } - - Steps[ Steps.getItemCount() - 1 ].OutBuf = 2; - - if( upstep != -1 ) - { - extendUpsample( Steps[ upstep ], Steps[ upstep + 1 ]); - } - } - - /** - * Function calculates an optimal intermediate buffer length that will - * cover all needs of the specified filtering steps. This function should - * be called after the updateFilterStepBuffers() function. - * - * Function also updates resizing step's RPosBuf pointers to the filter - * bank and SrcOffs values. - * - * @param Steps Filtering steps. - * @param[out] Vars Variables object, will receive buffer size and length. - * @param ResElIncr Resulting (final) element increment, used to produce - * de-interleaved result. For horizontal processing this value is equal - * to last step's OutLen, for vertical processing this value is equal to - * resulting image's width. - */ - - static void updateBufLenAndRPosPtrs( CFilterSteps& Steps, - CImageResizerVars& Vars, const int ResElIncr ) - { - int MaxPrefix[ 2 ] = { 0, 0 }; - int MaxLen[ 2 ] = { 0, 0 }; - int i; - - for( i = 0; i < Steps.getItemCount(); i++ ) - { - CFilterStep& fs = Steps[ i ]; - const int ib = fs.InBuf; - - if( fs.InPrefix > MaxPrefix[ ib ]) - { - MaxPrefix[ ib ] = fs.InPrefix; - } - - int l = fs.InLen + fs.InSuffix; - - if( l > MaxLen[ ib ]) - { - MaxLen[ ib ] = l; - } - - fs.InElIncr = fs.InPrefix + l; - - if( fs.OutBuf == 2 ) - { - break; - } - - const int ob = fs.OutBuf; - - if( fs.IsUpsample ) - { - if( fs.OutPrefix > MaxPrefix[ ob ]) - { - MaxPrefix[ ob ] = fs.OutPrefix; - } - - l = fs.OutLen + fs.OutSuffix; - - if( l > MaxLen[ ob ]) - { - MaxLen[ ob ] = l; - } - } - else - { - if( fs.OutLen > MaxLen[ ob ]) - { - MaxLen[ ob ] = fs.OutLen; - } - } - } - - // Update OutElIncr values of all steps. - - for( i = 0; i < Steps.getItemCount(); i++ ) - { - CFilterStep& fs = Steps[ i ]; - - if( fs.OutBuf == 2 ) - { - fs.OutElIncr = ResElIncr; - break; - } - - CFilterStep& fs2 = Steps[ i + 1 ]; - - if( fs.IsUpsample ) - { - fs.OutElIncr = fs.OutPrefix + fs.OutLen + fs.OutSuffix; - - if( fs.OutElIncr > fs2.InElIncr ) - { - fs2.InElIncr = fs.OutElIncr; - } - else - { - fs.OutElIncr = fs2.InElIncr; - } - } - else - { - fs.OutElIncr = fs2.InElIncr; - } - } - - // Update temporary buffer's length. - - for( i = 0; i < 2; i++ ) - { - Vars.BufLen[ i ] = MaxPrefix[ i ] + MaxLen[ i ]; - Vars.BufOffs[ i ] = MaxPrefix[ i ]; - - if( Vars.packmode == 0 ) - { - Vars.BufOffs[ i ] *= Vars.ElCount; - } - - Vars.BufLen[ i ] *= Vars.ElCount; - } - - // Update RPosBuf pointers and SrcOffs. - - CFilterStep& fs = Steps[ Vars.ResizeStep ]; - typename CFilterStep :: CResizePos* rpos = &(*fs.RPosBuf)[ 0 ]; - const int em = ( fpclass :: packmode == 0 ? Vars.ElCount : 1 ); - const int FilterLenD21 = fs.FltBank -> getFilterLen() / 2 - 1; - - for( i = 0; i < fs.OutLen; i++ ) - { - rpos -> ftp = fs.FltBank -> getFilter( rpos -> fti ); - rpos -> SrcOffs = ( rpos -> SrcPosInt - FilterLenD21 ) * em; - rpos++; - } - } - - /** - * Function modifies the overall (DC) gain of the correction filter in the - * pre-built filtering steps array. - * - * @param Steps Filtering steps. - * @param m Multiplier to apply to the correction filter. - */ - - void modifyCorrFilterDCGain( CFilterSteps& Steps, const double m ) const - { - CBuffer< fptype >* Flt; - const int z = Steps.getItemCount() - 1; - - if( !Steps[ z ].IsUpsample && Steps[ z ].ResampleFactor == 1 ) - { - Flt = &Steps[ z ].Flt; - } - else - { - Flt = &Steps[ 0 ].Flt; - } - - int i; - - for( i = 0; i < Flt -> getCapacity(); i++ ) - { - (*Flt)[ i ] = (fptype) ( (double) (*Flt)[ i ] * m ); - } - } - - /** - * Function builds a map of used fractional delay filters based on the - * resizing positions buffer. - * - * @param fs Resizing step. - * @param[out] UsedFracMap Map of used fractional delay filters. - */ - - static void fillUsedFracMap( const CFilterStep& fs, - CBuffer< uint8_t >& UsedFracMap ) - { - const int FracCount = fs.FltBank -> getFracCount(); - UsedFracMap.increaseCapacity( FracCount, false ); - memset( &UsedFracMap[ 0 ], 0, FracCount * sizeof( UsedFracMap[ 0 ])); - - typename CFilterStep :: CResizePos* rpos = &(*fs.RPosBuf)[ 0 ]; - int i; - - for( i = 0; i < fs.OutLen; i++ ) - { - UsedFracMap[ rpos -> fti ] |= 1; - rpos++; - } - } - - /** - * Function calculates the overall filtering steps complexity per - * scanline. Each complexity unit corresponds to a single multiply-add - * operation. Data copy and pointer math operations are not included in - * this calculation, it is assumed that they correlate to the multiply-add - * operations. Calculation also does not include final rounding, dithering - * and clamping operations since they cannot be optimized out anyway. - * - * Calculation of the CRPosBuf buffer is not included since it cannot be - * avoided. - * - * This function should be called after the updateFilterStepBuffers() - * function. - * - * @param Steps Filtering steps array. - * @param Vars Variables object. - * @param UsedFracMap The map of used fractional delay filters. - * @param ScanlineCount Scanline count. - */ - - static int calcComplexity( const CFilterSteps& Steps, - const CImageResizerVars& Vars, const CBuffer< uint8_t >& UsedFracMap, - const int ScanlineCount ) - { - int fcnum; // Filter complexity multiplier numerator. - int fcdenom; // Filter complexity multiplier denominator. - - if( Vars.packmode != 0 ) - { - fcnum = 1; - fcdenom = 1; - } - else - { - // In interleaved processing mode, filters require 1 less - // multiplication per 2 multiply-add instructions. - - fcnum = 3; - fcdenom = 4; - } - - int s = 0; // Complexity per one scanline. - int s2 = 0; // Complexity per all scanlines. - int i; - - for( i = 0; i < Steps.getItemCount(); i++ ) - { - const CFilterStep& fs = Steps[ i ]; - - s2 += 65 * fs.Flt.getCapacity(); // Filter creation complexity. - - if( fs.IsUpsample ) - { - if( fs.FltOrig.getCapacity() > 0 ) - { - continue; - } - - s += ( fs.Flt.getCapacity() * - ( fs.InPrefix + fs.InLen + fs.InSuffix ) + - fs.SuffixDC.getCapacity() + fs.PrefixDC.getCapacity() ) * - Vars.ElCount; - } - else - if( fs.ResampleFactor == 0 ) - { - s += fs.FltBank -> getFilterLen() * - ( fs.FltBank -> getOrder() + Vars.ElCount ) * fs.OutLen; - - s2 += fs.FltBank -> calcInitComplexity( UsedFracMap ); - } - else - { - s += fs.Flt.getCapacity() * Vars.ElCount * fs.OutLen * - fcnum / fcdenom; - } - } - - return( s + s2 / ScanlineCount ); - } - - /** - * @brief Thread-isolated data used for scanline processing. - * - * This structure holds data necessary for image's horizontal or vertical - * scanline processing, including scanline processing queue. - * - * @tparam Tin Source element data type. Intermediate buffers store data - * in floating point format. - * @tparam Tout Destination element data type. Intermediate buffers store - * data in floating point format. - */ - - template< class Tin, class Tout > - class CThreadData : public CImageResizerThreadPool :: CWorkload - { - public: - virtual void process() - { - processScanlineQueue(); - } - - /** - * This enumeration lists possible scanline operations. - */ - - enum EScanlineOperation - { - sopResizeH, ///< Resize horizontal scanline. - ///< - sopResizeV, ///< Resize vertical scanline. - ///< - sopDitherAndUnpackH, ///< Dither and unpack horizontal scanline. - ///< - sopUnpackH ///< Unpack horizontal scanline. - ///< - }; - - /** - * Function initializes *this thread data object and assigns certain - * variables provided by the higher level code. - * - * @param aThreadIndex Index of this thread data (0-based). - * @param aThreadCount Total number of threads used during processing. - * @param aSteps Filtering steps. - * @param aVars Image resizer variables. - */ - - void init( const int aThreadIndex, const int aThreadCount, - const CFilterSteps& aSteps, const CImageResizerVars& aVars ) - { - ThreadIndex = aThreadIndex; - ThreadCount = aThreadCount; - Steps = &aSteps; - Vars = &aVars; - } - - /** - * Function initializes scanline processing queue, and updates - * capacities of intermediate buffers. - * - * @param aOp Operation to perform over scanline. - * @param TotalLines The total number of scanlines that will be - * processed by all threads. - * @param aSrcLen Source scanline length in pixels. - * @param aSrcIncr Source scanline buffer increment. Ignored in - * horizontal scanline processing. - * @param aResIncr Resulting scanline buffer increment. Ignored in - * horizontal scanline processing. - */ - - void initScanlineQueue( const EScanlineOperation aOp, - const int TotalLines, const int aSrcLen, const int aSrcIncr = 0, - const int aResIncr = 0 ) - { - const int l = Vars -> BufLen[ 0 ] + Vars -> BufLen[ 1 ]; - - if( Bufs.getCapacity() < l ) - { - Bufs.alloc( l, fpclass :: fpalign ); - } - - BufPtrs[ 0 ] = Bufs + Vars -> BufOffs[ 0 ]; - BufPtrs[ 1 ] = Bufs + Vars -> BufLen[ 0 ] + Vars -> BufOffs[ 1 ]; - - int j; - int ml = 0; - - for( j = 0; j < Steps -> getItemCount(); j++ ) - { - const CFilterStep& fs = (*Steps)[ j ]; - - if( fs.ResampleFactor == 0 && - ml < fs.FltBank -> getFilterLen() ) - { - ml = fs.FltBank -> getFilterLen(); - } - } - - TmpFltBuf.alloc( ml, fpclass :: fpalign ); - ScanlineOp = aOp; - SrcLen = aSrcLen; - SrcIncr = aSrcIncr; - ResIncr = aResIncr; - QueueLen = 0; - Queue.increaseCapacity(( TotalLines + ThreadCount - 1 ) / - ThreadCount, false ); - } - - /** - * Function adds a scanline to the queue buffer. The - * initScanlineQueue() function should be called before calling this - * function. The number of calls to this add function should not - * exceed the TotalLines spread over all threads. - * - * @param SrcBuf Source scanline buffer. - * @param ResBuf Resulting scanline buffer. - */ - - void addScanlineToQueue( void* const SrcBuf, void* const ResBuf ) - { - Queue[ QueueLen ].SrcBuf = SrcBuf; - Queue[ QueueLen ].ResBuf = ResBuf; - QueueLen++; - } - - /** - * Function processes all queued scanlines. - */ - - void processScanlineQueue() - { - int i; - - switch( ScanlineOp ) - { - case sopResizeH: - { - for( i = 0; i < QueueLen; i++ ) - { - resizeScanlineH( (Tin*) Queue[ i ].SrcBuf, - (fptype*) Queue[ i ].ResBuf ); - } - - break; - } - - case sopResizeV: - { - for( i = 0; i < QueueLen; i++ ) - { - resizeScanlineV( (fptype*) Queue[ i ].SrcBuf, - (fptype*) Queue[ i ].ResBuf ); - } - - break; - } - - case sopDitherAndUnpackH: - { - if( Vars -> UseSRGBGamma ) - { - for( i = 0; i < QueueLen; i++ ) - { - CFilterStep :: applySRGBGamma( - (fptype*) Queue[ i ].SrcBuf, SrcLen, *Vars ); - - Ditherer.dither( (fptype*) Queue[ i ].SrcBuf ); - - CFilterStep :: unpackScanline( - (fptype*) Queue[ i ].SrcBuf, - (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars ); - } - } - else - { - for( i = 0; i < QueueLen; i++ ) - { - Ditherer.dither( (fptype*) Queue[ i ].SrcBuf ); - - CFilterStep :: unpackScanline( - (fptype*) Queue[ i ].SrcBuf, - (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars ); - } - } - - break; - } - - case sopUnpackH: - { - if( Vars -> UseSRGBGamma ) - { - for( i = 0; i < QueueLen; i++ ) - { - CFilterStep :: applySRGBGamma( - (fptype*) Queue[ i ].SrcBuf, SrcLen, *Vars ); - - CFilterStep :: unpackScanline( - (fptype*) Queue[ i ].SrcBuf, - (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars ); - } - } - else - { - for( i = 0; i < QueueLen; i++ ) - { - CFilterStep :: unpackScanline( - (fptype*) Queue[ i ].SrcBuf, - (Tout*) Queue[ i ].ResBuf, SrcLen, *Vars ); - } - } - - break; - } - } - } - - /** - * Function returns ditherer object associated with *this thread data - * object. - */ - - CDitherer& getDitherer() - { - return( Ditherer ); - } - - private: - int ThreadIndex; ///< Thread index. - ///< - int ThreadCount; ///< Thread count. - ///< - const CFilterSteps* Steps; ///< Filtering steps. - ///< - const CImageResizerVars* Vars; ///< Image resizer variables. - ///< - CBuffer< fptype > Bufs; ///< Flip-flop intermediate buffers. - ///< - fptype* BufPtrs[ 3 ]; ///< Flip-flop buffer pointers (referenced by - ///< filtering step's InBuf and OutBuf indices). - ///< - CBuffer< fptype > TmpFltBuf; ///< Temporary buffer used in the - ///< doResize() function, aligned by fpclass :: fpalign. - ///< - EScanlineOperation ScanlineOp; ///< Operation to perform over - ///< scanline. - ///< - int SrcLen; ///< Source scanline length in the last queue. - ///< - int SrcIncr; ///< Source scanline buffer increment in the last queue. - ///< - int ResIncr; ///< Resulting scanline buffer increment in the last - ///< queue. - ///< - CDitherer Ditherer; ///< Ditherer object to use. - ///< - - /** - * @brief Scanline processing queue item. - * - * Scanline processing queue item. - */ - - struct CQueueItem - { - void* SrcBuf; ///< Source scanline buffer, will by typecasted to - ///< Tin or fptype*. - ///< - void* ResBuf; ///< Resulting scanline buffer, will by typecasted - ///< to Tout or fptype*. - ///< - }; - - CBuffer< CQueueItem > Queue; ///< Scanline processing queue. - ///< - int QueueLen; ///< Queue length. - ///< - - /** - * Function resizes a single horizontal scanline. - * - * @param SrcBuf Source scanline buffer. Can be either horizontal or - * vertical. - * @param ResBuf Resulting scanline buffer. - */ - - void resizeScanlineH( const Tin* const SrcBuf, fptype* const ResBuf ) - { - (*Steps)[ 0 ].packScanline( SrcBuf, BufPtrs[ 0 ], SrcLen ); - BufPtrs[ 2 ] = ResBuf; - int j; - - for( j = 0; j < Steps -> getItemCount(); j++ ) - { - const CFilterStep& fs = (*Steps)[ j ]; - fs.prepareInBuf( BufPtrs[ fs.InBuf ]); - const int DstIncr = - ( Vars -> packmode == 0 ? Vars -> ElCount : 1 ); - - if( fs.ResampleFactor != 0 ) - { - if( fs.IsUpsample ) - { - fs.doUpsample( BufPtrs[ fs.InBuf ], - BufPtrs[ fs.OutBuf ]); - } - else - { - fs.doFilter( BufPtrs[ fs.InBuf ], - BufPtrs[ fs.OutBuf ], DstIncr ); - } - } - else - { - fs.doResize( BufPtrs[ fs.InBuf ], BufPtrs[ fs.OutBuf ], - DstIncr, TmpFltBuf ); - } - } - } - - /** - * Function resizes a single vertical scanline. - * - * @param SrcBuf Source scanline buffer. Can be either horizontal or - * vertical. - * @param ResBuf Resulting scanline buffer. - */ - - void resizeScanlineV( const fptype* const SrcBuf, - fptype* const ResBuf ) - { - (*Steps)[ 0 ].convertVtoH( SrcBuf, BufPtrs[ 0 ], SrcLen, - SrcIncr ); - - BufPtrs[ 2 ] = ResBuf; - int j; - - for( j = 0; j < Steps -> getItemCount(); j++ ) - { - const CFilterStep& fs = (*Steps)[ j ]; - fs.prepareInBuf( BufPtrs[ fs.InBuf ]); - const int DstIncr = ( fs.OutBuf == 2 ? ResIncr : - ( Vars -> packmode == 0 ? Vars -> ElCount : 1 )); - - if( fs.ResampleFactor != 0 ) - { - if( fs.IsUpsample ) - { - fs.doUpsample( BufPtrs[ fs.InBuf ], - BufPtrs[ fs.OutBuf ]); - } - else - { - fs.doFilter( BufPtrs[ fs.InBuf ], - BufPtrs[ fs.OutBuf ], DstIncr ); - } - } - else - { - fs.doResize( BufPtrs[ fs.InBuf ], BufPtrs[ fs.OutBuf ], - DstIncr, TmpFltBuf ); - } - } - } - }; -}; - -#undef AVIR_PI -#undef AVIR_PId2 - -} // namespace avir - -#endif // AVIR_CIMAGERESIZER_INCLUDED diff --git a/Modules/gin/3rdparty/avir/avir_dil.h b/Modules/gin/3rdparty/avir/avir_dil.h deleted file mode 100755 index 35ed97f..0000000 --- a/Modules/gin/3rdparty/avir/avir_dil.h +++ /dev/null @@ -1,1012 +0,0 @@ -//$ nobt -//$ nocpp - -/** - * @file avir_dil.h - * - * @brief Inclusion file for de-interleaved image resizing functions. - * - * This file includes the "CImageResizerFilterStepDIL" class which implements - * image resizing functions in de-interleaved mode. - * - * AVIR Copyright (c) 2015-2019 Aleksey Vaneev - */ - -namespace avir { - -/** - * @brief De-interleaved filtering steps implementation class. - * - * This class implements scanline filtering functions in de-interleaved mode. - * This means that pixels are processed in groups. - * - * @tparam fptype Floating point type to use for storing pixel elements. - * SIMD types cannot be used. - * @tparam fptypesimd The SIMD type used to store a pack of "fptype" values. - */ - -template< class fptype, class fptypesimd > -class CImageResizerFilterStepDIL : - public CImageResizerFilterStep< fptype, fptype > -{ -public: - using CImageResizerFilterStep< fptype, fptype > :: IsUpsample; - using CImageResizerFilterStep< fptype, fptype > :: ResampleFactor; - using CImageResizerFilterStep< fptype, fptype > :: Flt; - using CImageResizerFilterStep< fptype, fptype > :: FltOrig; - using CImageResizerFilterStep< fptype, fptype > :: FltLatency; - using CImageResizerFilterStep< fptype, fptype > :: Vars; - using CImageResizerFilterStep< fptype, fptype > :: InLen; - using CImageResizerFilterStep< fptype, fptype > :: InPrefix; - using CImageResizerFilterStep< fptype, fptype > :: InSuffix; - using CImageResizerFilterStep< fptype, fptype > :: InElIncr; - using CImageResizerFilterStep< fptype, fptype > :: OutLen; - using CImageResizerFilterStep< fptype, fptype > :: OutPrefix; - using CImageResizerFilterStep< fptype, fptype > :: OutSuffix; - using CImageResizerFilterStep< fptype, fptype > :: OutElIncr; - using CImageResizerFilterStep< fptype, fptype > :: PrefixDC; - using CImageResizerFilterStep< fptype, fptype > :: SuffixDC; - using CImageResizerFilterStep< fptype, fptype > :: RPosBuf; - using CImageResizerFilterStep< fptype, fptype > :: FltBank; - using CImageResizerFilterStep< fptype, fptype > :: EdgePixelCount; - - /** - * Function performs "packing" (de-interleaving) of a scanline and type - * conversion. If required, the sRGB gamma correction is applied. - * - * @param ip0 Input scanline, pixel elements interleaved. - * @param op0 Output scanline, pixel elements are grouped, "l" elements - * apart. - * @param l The number of pixels to "pack". - */ - - template< class Tin > - void packScanline( const Tin* const ip0, fptype* const op0, - const int l ) const - { - const int ElCount = Vars -> ElCount; - int j; - - if( !Vars -> UseSRGBGamma ) - { - for( j = 0; j < ElCount; j++ ) - { - const Tin* ip = ip0 + j; - fptype* const op = op0 + j * InElIncr; - int i; - - for( i = 0; i < l; i++ ) - { - op[ i ] = (fptype) *ip; - ip += ElCount; - } - } - } - else - { - const fptype gm = (fptype) Vars -> InGammaMult; - - for( j = 0; j < ElCount; j++ ) - { - const Tin* ip = ip0 + j; - fptype* const op = op0 + j * InElIncr; - int i; - - for( i = 0; i < l; i++ ) - { - op[ i ] = convertSRGB2Lin( (fptype) *ip * gm ); - ip += ElCount; - } - } - } - } - - /** - * Function applies Linear to sRGB gamma correction to the specified - * scanline. - * - * @param p Scanline. - * @param l The number of pixels to de-linearize. - * @param Vars0 Image resizing-related variables. - */ - - static void applySRGBGamma( fptype* const p0, const int l, - const CImageResizerVars& Vars0 ) - { - const int ElCount = Vars0.ElCount; - const fptype gm = (fptype) Vars0.OutGammaMult; - int j; - - for( j = 0; j < ElCount; j++ ) - { - fptype* const p = p0 + j * l; - int i; - - for( i = 0; i < l; i++ ) - { - p[ i ] = convertLin2SRGB( p[ i ]) * gm; - } - } - } - - /** - * Function converts vertical scanline to horizontal scanline. This - * function is called by the image resizer when image is resized - * vertically. This means that the vertical scanline is stored in the - * same format produced by the packScanline() and maintained by other - * filtering functions. - * - * @param ip Input vertical scanline, pixel elements are grouped, SrcLen - * elements apart. - * @param op Output buffer (temporary buffer used during resizing), pixel - * elements are grouped, "l" elements apart. - * @param SrcLen The number of pixels in the input scanline, also used to - * calculate input buffer increment. - * @param SrcIncr Input buffer increment to the next vertical pixel. - */ - - void convertVtoH( const fptype* ip, fptype* op, const int SrcLen, - const int SrcIncr ) const - { - const int ElCount = Vars -> ElCount; - const int SrcElIncr = SrcIncr / ElCount; - const int ips1 = SrcElIncr; - const int ips2 = SrcElIncr * 2; - const int ips3 = SrcElIncr * 3; - const int ops1 = InElIncr; - const int ops2 = InElIncr * 2; - const int ops3 = InElIncr * 3; - int j; - - if( ElCount == 1 ) - { - for( j = 0; j < SrcLen; j++ ) - { - op[ 0 ] = ip[ 0 ]; - ip += SrcIncr; - op++; - } - } - else - if( ElCount == 4 ) - { - for( j = 0; j < SrcLen; j++ ) - { - op[ 0 ] = ip[ 0 ]; - op[ ops1 ] = ip[ ips1 ]; - op[ ops2 ] = ip[ ips2 ]; - op[ ops3 ] = ip[ ips3 ]; - ip += SrcIncr; - op++; - } - } - else - if( ElCount == 3 ) - { - for( j = 0; j < SrcLen; j++ ) - { - op[ 0 ] = ip[ 0 ]; - op[ ops1 ] = ip[ ips1 ]; - op[ ops2 ] = ip[ ips2 ]; - ip += SrcIncr; - op++; - } - } - else - if( ElCount == 2 ) - { - for( j = 0; j < SrcLen; j++ ) - { - op[ 0 ] = ip[ 0 ]; - op[ ops1 ] = ip[ ips1 ]; - ip += SrcIncr; - op++; - } - } - } - - /** - * Function performs "unpacking" of a scanline and type conversion - * (truncation is used when floating point is converted to integer). - * The unpacking function assumes that scanline is stored in the style - * produced by the packScanline() function. - * - * @param ip0 Input scanline, pixel elements are grouped, "l" elements - * apart. - * @param op0 Output scanline, pixel elements are interleaved. - * @param l The number of pixels to "unpack". - * @param Vars0 Image resizing-related variables. ElCount is assumed to be - * equal to ElCountIO. - */ - - template< class Tout > - static void unpackScanline( const fptype* const ip0, Tout* const op0, - const int l, const CImageResizerVars& Vars0 ) - { - const int ElCount = Vars0.ElCount; - int j; - - for( j = 0; j < ElCount; j++ ) - { - const fptype* const ip = ip0 + j * l; - Tout* op = op0 + j; - int i; - - for( i = 0; i < l; i++ ) - { - *op = (Tout) ip[ i ]; - op += ElCount; - } - } - } - - /** - * Function prepares input scanline buffer for *this filtering step. - * Left- and right-most pixels are replicated to make sure no buffer - * overrun happens. Such approach also allows to bypass any pointer - * range checks. - * - * @param Src Source buffer. - */ - - void prepareInBuf( fptype* Src ) const - { - if( IsUpsample || InPrefix + InSuffix == 0 ) - { - return; - } - - int j; - - for( j = 0; j < Vars -> ElCount; j++ ) - { - replicateArray( Src, 1, Src - InPrefix, InPrefix, 1 ); - fptype* const Src2 = Src + InLen - 1; - replicateArray( Src2, 1, Src2 + 1, InSuffix, 1 ); - Src += InElIncr; - } - } - - /** - * Function peforms scanline upsampling with filtering. - * - * @param Src Source scanline buffer (length = this -> InLen). Source - * scanline increment will be equal to ElCount. - * @param Dst Destination scanline buffer. - */ - - void doUpsample( const fptype* Src, fptype* Dst ) const - { - const int elalign = Vars -> elalign; - const int opstep = ResampleFactor; - const fptype* const f = Flt; - const int flen = Flt.getCapacity(); - int l; - int i; - int j; - - for( j = 0; j < Vars -> ElCount; j++ ) - { - const fptype* ip = Src; - fptype* op0 = &Dst[ -OutPrefix ]; - memset( op0, 0, ( OutPrefix + OutLen + OutSuffix ) * - sizeof( fptype )); - - if( FltOrig.getCapacity() > 0 ) - { - // Do not perform filtering, only upsample. - - op0 += OutPrefix % ResampleFactor; - l = OutPrefix / ResampleFactor; - - while( l > 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0 += opstep; - l--; - } - - l = InLen - 1; - - while( l > 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0 += opstep; - ip++; - l--; - } - - l = OutSuffix / ResampleFactor; - - while( l >= 0 ) - { - op0[ 0 ] = ip[ 0 ]; - op0 += opstep; - l--; - } - - Src += InElIncr; - Dst += OutElIncr; - continue; - } - - l = InPrefix; - fptypesimd ipv = (fptypesimd) ip[ 0 ]; - - while( l > 0 ) - { - for( i = 0; i < flen; i += elalign ) - { - fptypesimd :: addu( op0 + i, - fptypesimd :: load( f + i ) * ipv ); - } - - op0 += opstep; - l--; - } - - l = InLen - 1; - - while( l > 0 ) - { - ipv = (fptypesimd) ip[ 0 ]; - - for( i = 0; i < flen; i += elalign ) - { - fptypesimd :: addu( op0 + i, - fptypesimd :: load( f + i ) * ipv ); - } - - ip++; - op0 += opstep; - l--; - } - - l = InSuffix; - ipv = (fptypesimd) ip[ 0 ]; - - while( l >= 0 ) - { - for( i = 0; i < flen; i += elalign ) - { - fptypesimd :: addu( op0 + i, - fptypesimd :: load( f + i ) * ipv ); - } - - op0 += opstep; - l--; - } - - const fptype* dc = SuffixDC; - l = SuffixDC.getCapacity(); - - for( i = 0; i < l; i += elalign ) - { - fptypesimd :: addu( op0 + i, - fptypesimd :: load( dc + i ) * ipv ); - } - - ipv = (fptypesimd) Src[ 0 ]; - op0 = Dst - InPrefix * opstep; - dc = PrefixDC; - l = PrefixDC.getCapacity(); - - for( i = 0; i < l; i += elalign ) - { - fptypesimd :: addu( op0 + i, - fptypesimd :: load( dc + i ) * ipv ); - } - - Src += InElIncr; - Dst += OutElIncr; - } - } - - /** - * Function peforms scanline filtering with optional downsampling. - * Function makes use of the symmetry of the filter. - * - * @param Src Source scanline buffer (length = this -> InLen). Source - * scanline increment will be equal to 1. - * @param Dst Destination scanline buffer. - * @param DstIncr Destination scanline buffer increment, used for - * horizontal or vertical scanline stepping. - */ - - void doFilter( const fptype* const Src, fptype* Dst, - const int DstIncr ) const - { - const int ElCount = Vars -> ElCount; - const int elalign = Vars -> elalign; - const fptype* const f = &Flt[ 0 ]; - const int flen = Flt.getCapacity(); - const int ipstep = ResampleFactor; - int i; - int j; - - if( ElCount == 1 ) - { - const fptype* ip = Src - EdgePixelCount * ipstep - FltLatency; - fptype* op = Dst; - int l = OutLen; - - while( l > 0 ) - { - fptypesimd s = fptypesimd :: load( f ) * - fptypesimd :: loadu( ip ); - - for( i = elalign; i < flen; i += elalign ) - { - s += fptypesimd :: load( f + i ) * - fptypesimd :: loadu( ip + i ); - } - - op[ 0 ] = s.hadd(); - op += DstIncr; - ip += ipstep; - l--; - } - } - else - if( DstIncr == 1 ) - { - for( j = 0; j < ElCount; j++ ) - { - const fptype* ip = Src - EdgePixelCount * ipstep - - FltLatency + j * InElIncr; - - fptype* op = Dst + j * OutElIncr; - int l = OutLen; - - while( l > 0 ) - { - fptypesimd s = fptypesimd :: load( f ) * - fptypesimd :: loadu( ip ); - - for( i = elalign; i < flen; i += elalign ) - { - s += fptypesimd :: load( f + i ) * - fptypesimd :: loadu( ip + i ); - } - - op[ 0 ] = s.hadd(); - op += DstIncr; - ip += ipstep; - l--; - } - } - } - else - { - const fptype* ip0 = Src - EdgePixelCount * ipstep - FltLatency; - fptype* op0 = Dst; - int l = OutLen; - - while( l > 0 ) - { - const fptype* ip = ip0; - fptype* op = op0; - - for( j = 0; j < ElCount; j++ ) - { - fptypesimd s = fptypesimd :: load( f ) * - fptypesimd :: loadu( ip ); - - for( i = elalign; i < flen; i += elalign ) - { - s += fptypesimd :: load( f + i ) * - fptypesimd :: loadu( ip + i ); - } - - op[ 0 ] = s.hadd(); - ip += InElIncr; - op += OutElIncr; - } - - ip0 += ipstep; - op0 += DstIncr; - l--; - } - } - } - - /** - * Function performs resizing of a single scanline. This function does - * not "know" about the length of the source scanline buffer. This buffer - * should be padded with enough pixels so that ( SrcPos - FilterLenD2 ) is - * always >= 0 and ( SrcPos + ( DstLineLen - 1 ) * k + FilterLenD2 + 1 ) - * does not exceed source scanline's buffer length. SrcLine's increment is - * assumed to be equal to 1. - * - * @param SrcLine Source scanline buffer. - * @param DstLine Destination (resized) scanline buffer. - * @param DstLineIncr Destination scanline position increment, used for - * horizontal or vertical scanline stepping. - * @param xx Temporary buffer, of size FltBank -> getFilterLen(), must be - * aligned by fpclass :: fpalign. - */ - - void doResize( const fptype* SrcLine, fptype* DstLine, - int DstLineIncr, fptype* const xx ) const - { - const int IntFltLen = FltBank -> getFilterLen(); - const int ElCount = Vars -> ElCount; - const int elalign = Vars -> elalign; - const typename CImageResizerFilterStep< fptype, fptype > :: - CResizePos* rpos = &(*RPosBuf)[ 0 ]; - - int DstLineLen = OutLen; - int i; - int j; - -#define AVIR_RESIZE_PART1 \ - while( DstLineLen > 0 ) \ - { \ - const fptypesimd x = (fptypesimd) rpos -> x; \ - const fptype* ftp = rpos -> ftp; \ - const fptype* ftp2 = rpos -> ftp + IntFltLen; \ - const fptype* Src = SrcLine + rpos -> SrcOffs; - -#define AVIR_RESIZE_PART1nx \ - while( DstLineLen > 0 ) \ - { \ - const fptype* ftp = rpos -> ftp; \ - const fptype* Src = SrcLine + rpos -> SrcOffs; - -#define AVIR_RESIZE_PART2 \ - DstLine += DstLineIncr; \ - rpos++; \ - DstLineLen--; \ - } - - if( ElCount == 1 ) - { - if( FltBank -> getOrder() == 1 ) - { - AVIR_RESIZE_PART1 - - fptypesimd sum = ( fptypesimd :: load( ftp ) + - fptypesimd :: load( ftp2 ) * x ) * - fptypesimd :: loadu( Src ); - - for( i = elalign; i < IntFltLen; i += elalign ) - { - sum += ( fptypesimd :: load( ftp + i ) + - fptypesimd :: load( ftp2 + i ) * x ) * - fptypesimd :: loadu( Src + i ); - } - - DstLine[ 0 ] = sum.hadd(); - - AVIR_RESIZE_PART2 - } - else - { - AVIR_RESIZE_PART1nx - - fptypesimd sum = fptypesimd :: load( ftp ) * - fptypesimd :: loadu( Src ); - - for( i = elalign; i < IntFltLen; i += elalign ) - { - sum += fptypesimd :: load( ftp + i ) * - fptypesimd :: loadu( Src + i ); - } - - DstLine[ 0 ] = sum.hadd(); - - AVIR_RESIZE_PART2 - } - } - else - if( DstLineIncr == 1 ) - { - // Horizontal-oriented processing, element loop is outer. - - const int SrcIncr = InElIncr; - const int DstLineElIncr = OutElIncr - DstLineIncr * DstLineLen; - - if( FltBank -> getOrder() == 1 ) - { - for( j = 0; j < ElCount; j++ ) - { - AVIR_RESIZE_PART1 - - fptypesimd sum = 0.0; - - for( i = 0; i < IntFltLen; i += elalign ) - { - sum += ( fptypesimd :: load( ftp + i ) + - fptypesimd :: load( ftp2 + i ) * x ) * - fptypesimd :: loadu( Src + i ); - } - - DstLine[ 0 ] = sum.hadd(); - - AVIR_RESIZE_PART2 - - DstLine += DstLineElIncr; - SrcLine += SrcIncr; - DstLineLen = OutLen; - rpos = &(*RPosBuf)[ 0 ]; - } - } - else - { - for( j = 0; j < ElCount; j++ ) - { - AVIR_RESIZE_PART1nx - - fptypesimd sum = fptypesimd :: load( ftp ) * - fptypesimd :: loadu( Src ); - - for( i = elalign; i < IntFltLen; i += elalign ) - { - sum += fptypesimd :: load( ftp + i ) * - fptypesimd :: loadu( Src + i ); - } - - DstLine[ 0 ] = sum.hadd(); - - AVIR_RESIZE_PART2 - - DstLine += DstLineElIncr; - SrcLine += SrcIncr; - DstLineLen = OutLen; - rpos = &(*RPosBuf)[ 0 ]; - } - } - } - else - { - const int SrcIncr = InElIncr; - const int DstLineElIncr = OutElIncr; - DstLineIncr -= DstLineElIncr * ElCount; - - if( FltBank -> getOrder() == 1 ) - { - AVIR_RESIZE_PART1 - - for( i = 0; i < IntFltLen; i += elalign ) - { - ( fptypesimd :: load( ftp + i ) + - fptypesimd :: load( ftp2 + i ) * x ).store( xx + i ); - } - - for( j = 0; j < ElCount; j++ ) - { - fptypesimd sum = fptypesimd :: load( xx ) * - fptypesimd :: loadu( Src ); - - for( i = elalign; i < IntFltLen; i += elalign ) - { - sum += fptypesimd :: load( xx + i ) * - fptypesimd :: loadu( Src + i ); - } - - DstLine[ 0 ] = sum.hadd(); - DstLine += DstLineElIncr; - Src += SrcIncr; - } - - AVIR_RESIZE_PART2 - } - else - { - AVIR_RESIZE_PART1nx - - for( j = 0; j < ElCount; j++ ) - { - fptypesimd sum = fptypesimd :: load( ftp ) * - fptypesimd :: loadu( Src ); - - for( i = elalign; i < IntFltLen; i += elalign ) - { - sum += fptypesimd :: load( ftp + i ) * - fptypesimd :: loadu( Src + i ); - } - - DstLine[ 0 ] = sum.hadd(); - DstLine += DstLineElIncr; - Src += SrcIncr; - } - - AVIR_RESIZE_PART2 - } - } - -#undef AVIR_RESIZE_PART2 -#undef AVIR_RESIZE_PART1nx -#undef AVIR_RESIZE_PART1 - } -}; - -/** - * @brief Image resizer's default de-interleaved dithering class. - * - * This class defines an object that performs rounding, clipping and dithering - * operations over horizontal scanline pixels before scanline is stored in the - * output buffer. - * - * This ditherer implementation uses de-interleaved SIMD algorithm. - * - * @tparam fptype Floating point type to use for storing pixel data. SIMD - * types cannot be used. - * @tparam fptypesimd The SIMD type used to store a pack of "fptype" values. - */ - -template< class fptype, class fptypesimd > -class CImageResizerDithererDefDIL -{ -public: - /** - * Function initializes the ditherer object. - * - * @param aLen Scanline length in pixels to process. - * @param aVars Image resizing-related variables. - * @param aTrMul Bit-depth truncation multiplier. 1 - no additional - * truncation. - * @param aPkOut Peak output value allowed. - */ - - void init( const int aLen, const CImageResizerVars& aVars, - const double aTrMul, const double aPkOut ) - { - Len = aLen; - Vars = &aVars; - LenE = aLen * Vars -> ElCount; - TrMul0 = aTrMul; - PkOut0 = aPkOut; - } - - /** - * @return "True" if dithering is recursive relative to scanlines meaning - * multi-threaded execution is not supported by this dithering method. - */ - - static bool isRecursive() - { - return( false ); - } - - /** - * Function performs rounding and clipping operations. - * - * @param ResScanline The buffer containing the final scanline. - */ - - void dither( fptype* const ResScanline ) const - { - const int elalign = Vars -> elalign; - const fptypesimd c0 = 0.0; - const fptypesimd PkOut = (fptypesimd) PkOut0; - int j; - - if( TrMul0 == 1.0 ) - { - // Optimization - do not perform bit truncation. - - for( j = 0; j < LenE - elalign; j += elalign ) - { - const fptypesimd z0 = round( - fptypesimd :: loadu( ResScanline + j )); - - clamp( z0, c0, PkOut ).storeu( ResScanline + j ); - } - - const int lim = LenE - j; - const fptypesimd z0 = round( - fptypesimd :: loadu( ResScanline + j, lim )); - - clamp( z0, c0, PkOut ).storeu( ResScanline + j, lim ); - } - else - { - const fptypesimd TrMul = (fptypesimd) TrMul0; - - for( j = 0; j < LenE - elalign; j += elalign ) - { - const fptypesimd z0 = round( - fptypesimd :: loadu( ResScanline + j ) / TrMul ) * TrMul; - - clamp( z0, c0, PkOut ).storeu( ResScanline + j ); - } - - const int lim = LenE - j; - const fptypesimd z0 = round( - fptypesimd :: loadu( ResScanline + j, lim ) / TrMul ) * TrMul; - - clamp( z0, c0, PkOut ).storeu( ResScanline + j, lim ); - } - } - -protected: - int Len; ///< Scanline's length in pixels. - ///< - const CImageResizerVars* Vars; ///< Image resizing-related variables. - ///< - int LenE; ///< = LenE * ElCount. - ///< - double TrMul0; ///< Bit-depth truncation multiplier. - ///< - double PkOut0; ///< Peak output value allowed. - ///< -}; - -/** - * @brief Image resizer's error-diffusion dithering class, de-interleaved - * mode. - * - * This ditherer implements error-diffusion dithering which looks good, and - * whose results are compressed by PNG well. - * - * @tparam fptype Floating point type to use for storing pixel data. SIMD - * types cannot be used. - * @tparam fptypesimd Processing type, SIMD can be used. - */ - -template< class fptype, class fptypesimd > -class CImageResizerDithererErrdDIL -{ -public: - /** - * Function initializes the ditherer object. - * - * @param aLen Scanline length in pixels to process. - * @param aVars Image resizing-related variables. - * @param aTrMul Bit-depth truncation multiplier. 1 - no additional - * truncation. - * @param aPkOut Peak output value allowed. - */ - - void init( const int aLen, const CImageResizerVars& aVars, - const double aTrMul, const double aPkOut ) - { - Len = aLen; - Vars = &aVars; - LenE = aLen * Vars -> ElCount; - TrMul0 = aTrMul; - PkOut0 = aPkOut; - - ResScanlineDith0.alloc( LenE + Vars -> ElCount, sizeof( fptype )); - ResScanlineDith = ResScanlineDith0 + Vars -> ElCount; - int i; - - for( i = 0; i < LenE + Vars -> ElCount; i++ ) - { - ResScanlineDith0[ i ] = 0.0; - } - } - - static bool isRecursive() - { - return( true ); - } - - void dither( fptype* const ResScanline ) - { - const int ea = Vars -> elalign; - const fptypesimd c0 = 0.0; - const fptypesimd TrMul = (fptypesimd) TrMul0; - const fptypesimd PkOut = (fptypesimd) PkOut0; - int j; - - for( j = 0; j < LenE - ea; j += ea ) - { - fptypesimd :: addu( ResScanline + j, - fptypesimd :: loadu( ResScanlineDith + j )); - - c0.storeu( ResScanlineDith + j ); - } - - int lim = LenE - j; - fptypesimd :: addu( ResScanline + j, - fptypesimd :: loadu( ResScanlineDith + j, lim ), lim ); - - c0.storeu( ResScanlineDith + j, lim ); - - const int Len1 = Len - 1; - fptype* rs = ResScanline; - fptype* rsd = ResScanlineDith; - int i; - - for( i = 0; i < Vars -> ElCount; i++ ) - { - for( j = 0; j < Len1; j++ ) - { - // Perform rounding, noise estimation and saturation. - - fptype* const rsj = rs + j; - const fptype z0 = round( rsj[ 0 ] / TrMul ) * TrMul; - const fptype Noise = rsj[ 0 ] - z0; - rsj[ 0 ] = clamp( z0, (fptype) 0.0, PkOut ); - - fptype* const rsdj = rsd + j; - rsj[ 1 ] += Noise * (fptype) 0.364842; - rsdj[ -1 ] += Noise * (fptype) 0.207305; - rsdj[ 0 ] += Noise * (fptype) 0.364842; - rsdj[ 1 ] += Noise * (fptype) 0.063011; - } - - // Process the last pixel element in scanline. - - const fptype z1 = round( rs[ Len1 ] / TrMul ) * TrMul; - const fptype Noise2 = rs[ Len1 ] - z1; - rs[ Len1 ] = clamp( z1, c0, PkOut ); - - rsd[ Len1 - 1 ] += Noise2 * (fptype) 0.207305; - rsd[ Len1 ] += Noise2 * (fptype) 0.364842; - - rs += Len; - rsd += Len; - } - } - -protected: - int Len; ///< Scanline's length in pixels. - ///< - const CImageResizerVars* Vars; ///< Image resizing-related variables. - ///< - int LenE; ///< = LenE * ElCount. - ///< - double TrMul0; ///< Bit-depth truncation multiplier. - ///< - double PkOut0; ///< Peak output value allowed. - ///< - CBuffer< fptype > ResScanlineDith0; ///< Error propagation buffer for - ///< dithering, first pixel unused. - ///< - fptype* ResScanlineDith; ///< Error propagation buffer pointer which skips - ///< the first ElCount elements. - ///< -}; - -/** - * @brief Floating-point processing definition and abstraction class for - * de-interleaved processing. - * - * This class defines several constants and typedefs that point to classes - * that should be used by the image resizing algorithm. This implementation - * points to de-interleaved processing classes. - * - * @tparam afptype Floating point type to use for storing intermediate data - * and variables. SIMD types should not be used. - * @tparam afptypesimd SIMD type used to perform processing. - * @tparam adith Ditherer class to use during processing. - */ - -template< class afptype, class afptypesimd, - class adith = CImageResizerDithererDefDIL< afptype, afptypesimd > > -class fpclass_def_dil -{ -public: - typedef afptype fptype; ///< Floating-point type to use during processing. - ///< - typedef afptype fptypeatom; ///< Atomic type "fptype" consists of. - ///< - static const int fppack = 1; ///< The number of atomic types stored in a - ///< single "fptype" element. - ///< - static const int fpalign = sizeof( afptypesimd ); ///< Suggested alignment - ///< size in bytes. This is not a required alignment, because image - ///< resizing algorithm cannot be made to have a strictly aligned data - ///< access in all cases (e.g. de-interleaved interpolation cannot - ///< perform aligned accesses). - ///< - static const int elalign = sizeof( afptypesimd ) / sizeof( afptype ); ///< - ///< Length alignment of arrays of elements. This applies to filters - ///< and intermediate buffers: this constant forces filters and - ///< scanlines to have a length which is a multiple of this value, for - ///< more efficient SIMD implementation. - ///< - static const int packmode = 1; ///< 0 if interleaved packing, 1 if - ///< de-interleaved. - ///< - typedef CImageResizerFilterStepDIL< fptype, afptypesimd > CFilterStep; ///< - ///< Filtering step class to use during processing. - ///< - typedef adith CDitherer; ///< Ditherer class to use during processing. - ///< -}; - -} // namespace avir diff --git a/Modules/gin/3rdparty/avir/avir_float4_sse.h b/Modules/gin/3rdparty/avir/avir_float4_sse.h deleted file mode 100755 index 6d488f3..0000000 --- a/Modules/gin/3rdparty/avir/avir_float4_sse.h +++ /dev/null @@ -1,319 +0,0 @@ -//$ nobt -//$ nocpp - -/** - * @file avir_float4_sse.h - * - * @brief Inclusion file for the "float4" type. - * - * This file includes the "float4" SSE-based type used for SIMD variable - * storage and processing. - * - * AVIR Copyright (c) 2015-2019 Aleksey Vaneev - */ - -#ifndef AVIR_FLOAT4_SSE_INCLUDED -#define AVIR_FLOAT4_SSE_INCLUDED - -#include -#include - -namespace avir { - -/** - * @brief SIMD packed 4-float type. - * - * This class implements a packed 4-float type that can be used to perform - * parallel computation using SIMD instructions on SSE-enabled processors. - * This class can be used as the "fptype" argument of the avir::fpclass_def - * class. - */ - -class float4 -{ -public: - float4() - { - } - - float4( const float4& s ) - : value( s.value ) - { - } - - float4( const __m128 s ) - : value( s ) - { - } - - float4( const float s ) - : value( _mm_set1_ps( s )) - { - } - - float4& operator = ( const float4& s ) - { - value = s.value; - return( *this ); - } - - float4& operator = ( const __m128 s ) - { - value = s; - return( *this ); - } - - float4& operator = ( const float s ) - { - value = _mm_set1_ps( s ); - return( *this ); - } - - operator float () const - { - return( _mm_cvtss_f32( value )); - } - - /** - * @param p Pointer to memory from where the value should be loaded, - * should be 16-byte aligned. - * @return float4 value loaded from the specified memory location. - */ - - static float4 load( const float* const p ) - { - return( _mm_load_ps( p )); - } - - /** - * @param p Pointer to memory from where the value should be loaded, - * may have any alignment. - * @return float4 value loaded from the specified memory location. - */ - - static float4 loadu( const float* const p ) - { - return( _mm_loadu_ps( p )); - } - - /** - * @param p Pointer to memory from where the value should be loaded, - * may have any alignment. - * @param lim The maximum number of elements to load, >0. - * @return float4 value loaded from the specified memory location, with - * elements beyond "lim" set to 0. - */ - - static float4 loadu( const float* const p, int lim ) - { - if( lim > 2 ) - { - if( lim > 3 ) - { - return( _mm_loadu_ps( p )); - } - else - { - return( _mm_set_ps( 0.0f, p[ 2 ], p[ 1 ], p[ 0 ])); - } - } - else - { - if( lim == 2 ) - { - return( _mm_set_ps( 0.0f, 0.0f, p[ 1 ], p[ 0 ])); - } - else - { - return( _mm_load_ss( p )); - } - } - } - - /** - * Function stores *this value to the specified memory location. - * - * @param[out] p Output memory location, should be 16-byte aligned. - */ - - void store( float* const p ) const - { - _mm_store_ps( p, value ); - } - - /** - * Function stores *this value to the specified memory location. - * - * @param[out] p Output memory location, may have any alignment. - */ - - void storeu( float* const p ) const - { - _mm_storeu_ps( p, value ); - } - - /** - * Function stores "lim" lower elements of *this value to the specified - * memory location. - * - * @param[out] p Output memory location, may have any alignment. - * @param lim The number of lower elements to store, >0. - */ - - void storeu( float* const p, int lim ) const - { - if( lim > 2 ) - { - if( lim > 3 ) - { - _mm_storeu_ps( p, value ); - } - else - { - _mm_storel_pi( (__m64*) (void*) p, value ); - _mm_store_ss( p + 2, _mm_movehl_ps( value, value )); - } - } - else - { - if( lim == 2 ) - { - _mm_storel_pi( (__m64*) (void*) p, value ); - } - else - { - _mm_store_ss( p, value ); - } - } - } - - float4& operator += ( const float4& s ) - { - value = _mm_add_ps( value, s.value ); - return( *this ); - } - - float4& operator -= ( const float4& s ) - { - value = _mm_sub_ps( value, s.value ); - return( *this ); - } - - float4& operator *= ( const float4& s ) - { - value = _mm_mul_ps( value, s.value ); - return( *this ); - } - - float4& operator /= ( const float4& s ) - { - value = _mm_div_ps( value, s.value ); - return( *this ); - } - - float4 operator + ( const float4& s ) const - { - return( _mm_add_ps( value, s.value )); - } - - float4 operator - ( const float4& s ) const - { - return( _mm_sub_ps( value, s.value )); - } - - float4 operator * ( const float4& s ) const - { - return( _mm_mul_ps( value, s.value )); - } - - float4 operator / ( const float4& s ) const - { - return( _mm_div_ps( value, s.value )); - } - - /** - * @return Horizontal sum of elements. - */ - - float hadd() const - { - const __m128 v = _mm_add_ps( value, _mm_movehl_ps( value, value )); - const __m128 res = _mm_add_ss( v, _mm_shuffle_ps( v, v, 1 )); - return( _mm_cvtss_f32( res )); - } - - /** - * Function performs in-place addition of a value located in memory and - * the specified value. - * - * @param p Pointer to value where addition happens. May be unaligned. - * @param v Value to add. - */ - - static void addu( float* const p, const float4& v ) - { - ( loadu( p ) + v ).storeu( p ); - } - - /** - * Function performs in-place addition of a value located in memory and - * the specified value. Limited to the specfied number of elements. - * - * @param p Pointer to value where addition happens. May be unaligned. - * @param v Value to add. - * @param lim The element number limit, >0. - */ - - static void addu( float* const p, const float4& v, const int lim ) - { - ( loadu( p, lim ) + v ).storeu( p, lim ); - } - - __m128 value; ///< Packed value of 4 floats. - ///< -}; - -/** - * SIMD rounding function, exact result. - * - * @param v Value to round. - * @return Rounded SIMD value. - */ - -inline float4 round( const float4& v ) -{ - unsigned int prevrm = _MM_GET_ROUNDING_MODE(); - _MM_SET_ROUNDING_MODE( _MM_ROUND_NEAREST ); - - const __m128 res = _mm_cvtepi32_ps( _mm_cvtps_epi32( v.value )); - - _MM_SET_ROUNDING_MODE( prevrm ); - - return( res ); -} - -/** - * SIMD function "clamps" (clips) the specified packed values so that they are - * not lesser than "minv", and not greater than "maxv". - * - * @param Value Value to clamp. - * @param minv Minimal allowed value. - * @param maxv Maximal allowed value. - * @return The clamped value. - */ - -inline float4 clamp( const float4& Value, const float4& minv, - const float4& maxv ) -{ - return( _mm_min_ps( _mm_max_ps( Value.value, minv.value ), maxv.value )); -} - -typedef fpclass_def< avir :: float4, float > fpclass_float4; ///< - ///< Class that can be used as the "fpclass" template parameter of the - ///< avir::CImageResizer class to perform calculation using default - ///< interleaved algorithm, using SIMD float4 type. - ///< - -} // namespace avir - -#endif // AVIR_FLOAT4_SSE_INCLUDED diff --git a/Modules/gin/3rdparty/avir/avir_float8_avx.h b/Modules/gin/3rdparty/avir/avir_float8_avx.h deleted file mode 100755 index 5eb631f..0000000 --- a/Modules/gin/3rdparty/avir/avir_float8_avx.h +++ /dev/null @@ -1,359 +0,0 @@ -//$ nobt -//$ nocpp - -/** - * @file avir_float8_avx.h - * - * @brief Inclusion file for the "float8" type. - * - * This file includes the "float8" AVX-based type used for SIMD variable - * storage and processing. - * - * AVIR Copyright (c) 2015-2019 Aleksey Vaneev - */ - -#ifndef AVIR_FLOAT8_AVX_INCLUDED -#define AVIR_FLOAT8_AVX_INCLUDED - -#include -#include "avir_dil.h" - -namespace avir { - -/** - * @brief SIMD packed 8-float type. - * - * This class implements a packed 8-float type that can be used to perform - * parallel computation using SIMD instructions on AVX-enabled processors. - * This class can be used as the "fptype" argument of the avir::fpclass_def - * or avir::fpclass_def_dil class. - */ - -class float8 -{ -public: - float8() - { - } - - float8( const float8& s ) - : value( s.value ) - { - } - - float8( const __m256 s ) - : value( s ) - { - } - - float8( const float s ) - : value( _mm256_set1_ps( s )) - { - } - - float8& operator = ( const float8& s ) - { - value = s.value; - return( *this ); - } - - float8& operator = ( const __m256 s ) - { - value = s; - return( *this ); - } - - float8& operator = ( const float s ) - { - value = _mm256_set1_ps( s ); - return( *this ); - } - - operator float () const - { - return( _mm_cvtss_f32( _mm256_extractf128_ps( value, 0 ))); - } - - /** - * @param p Pointer to memory from where the value should be loaded, - * should be 32-byte aligned. - * @return float8 value loaded from the specified memory location. - */ - - static float8 load( const float* const p ) - { - return( _mm256_load_ps( p )); - } - - /** - * @param p Pointer to memory from where the value should be loaded, - * may have any alignment. - * @return float8 value loaded from the specified memory location. - */ - - static float8 loadu( const float* const p ) - { - return( _mm256_loadu_ps( p )); - } - - /** - * @param p Pointer to memory from where the value should be loaded, - * may have any alignment. - * @param lim The maximum number of elements to load, >0. - * @return float8 value loaded from the specified memory location, with - * elements beyond "lim" set to 0. - */ - - static float8 loadu( const float* const p, const int lim ) - { - __m128 lo; - __m128 hi; - - if( lim > 4 ) - { - lo = _mm_loadu_ps( p ); - hi = loadu4( p + 4, lim - 4 ); - } - else - { - lo = loadu4( p, lim ); - hi = _mm_setzero_ps(); - } - - return( _mm256_insertf128_ps( _mm256_castps128_ps256( lo ), hi, 1 )); - } - - /** - * Function stores *this value to the specified memory location. - * - * @param[out] p Output memory location, should be 32-byte aligned. - */ - - void store( float* const p ) const - { - _mm256_store_ps( p, value ); - } - - /** - * Function stores *this value to the specified memory location. - * - * @param[out] p Output memory location, may have any alignment. - */ - - void storeu( float* const p ) const - { - _mm256_storeu_ps( p, value ); - } - - /** - * Function stores "lim" lower elements of *this value to the specified - * memory location. - * - * @param[out] p Output memory location, may have any alignment. - * @param lim The number of lower elements to store, >0. - */ - - void storeu( float* p, int lim ) const - { - __m128 v; - - if( lim > 4 ) - { - _mm_storeu_ps( p, _mm256_extractf128_ps( value, 0 )); - v = _mm256_extractf128_ps( value, 1 ); - p += 4; - lim -= 4; - } - else - { - v = _mm256_extractf128_ps( value, 0 ); - } - - if( lim > 2 ) - { - if( lim > 3 ) - { - _mm_storeu_ps( p, v ); - } - else - { - _mm_storel_pi( (__m64*) p, v ); - _mm_store_ss( p + 2, _mm_movehl_ps( v, v )); - } - } - else - { - if( lim == 2 ) - { - _mm_storel_pi( (__m64*) p, v ); - } - else - { - _mm_store_ss( p, v ); - } - } - } - - float8& operator += ( const float8& s ) - { - value = _mm256_add_ps( value, s.value ); - return( *this ); - } - - float8& operator -= ( const float8& s ) - { - value = _mm256_sub_ps( value, s.value ); - return( *this ); - } - - float8& operator *= ( const float8& s ) - { - value = _mm256_mul_ps( value, s.value ); - return( *this ); - } - - float8& operator /= ( const float8& s ) - { - value = _mm256_div_ps( value, s.value ); - return( *this ); - } - - float8 operator + ( const float8& s ) const - { - return( _mm256_add_ps( value, s.value )); - } - - float8 operator - ( const float8& s ) const - { - return( _mm256_sub_ps( value, s.value )); - } - - float8 operator * ( const float8& s ) const - { - return( _mm256_mul_ps( value, s.value )); - } - - float8 operator / ( const float8& s ) const - { - return( _mm256_div_ps( value, s.value )); - } - - /** - * @return Horizontal sum of elements. - */ - - float hadd() const - { - __m128 v = _mm_add_ps( _mm256_extractf128_ps( value, 0 ), - _mm256_extractf128_ps( value, 1 )); - - v = _mm_hadd_ps( v, v ); - v = _mm_hadd_ps( v, v ); - return( _mm_cvtss_f32( v )); - } - - /** - * Function performs in-place addition of a value located in memory and - * the specified value. - * - * @param p Pointer to value where addition happens. May be unaligned. - * @param v Value to add. - */ - - static void addu( float* const p, const float8& v ) - { - ( loadu( p ) + v ).storeu( p ); - } - - /** - * Function performs in-place addition of a value located in memory and - * the specified value. Limited to the specfied number of elements. - * - * @param p Pointer to value where addition happens. May be unaligned. - * @param v Value to add. - * @param lim The element number limit, >0. - */ - - static void addu( float* const p, const float8& v, const int lim ) - { - ( loadu( p, lim ) + v ).storeu( p, lim ); - } - - __m256 value; ///< Packed value of 8 floats. - ///< - -private: - /** - * @param p Pointer to memory from where the value should be loaded, - * may have any alignment. - * @param lim The maximum number of elements to load, >0. - * @return __m128 value loaded from the specified memory location, with - * elements beyond "lim" set to 0. - */ - - static __m128 loadu4( const float* const p, const int lim ) - { - if( lim > 2 ) - { - if( lim > 3 ) - { - return( _mm_loadu_ps( p )); - } - else - { - return( _mm_set_ps( 0.0f, p[ 2 ], p[ 1 ], p[ 0 ])); - } - } - else - { - if( lim == 2 ) - { - return( _mm_set_ps( 0.0f, 0.0f, p[ 1 ], p[ 0 ])); - } - else - { - return( _mm_load_ss( p )); - } - } - } -}; - -/** - * SIMD rounding function, exact result. - * - * @param v Value to round. - * @return Rounded SIMD value. - */ - -inline float8 round( const float8& v ) -{ - return( _mm256_round_ps( v.value, - ( _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC ))); -} - -/** - * SIMD function "clamps" (clips) the specified packed values so that they are - * not lesser than "minv", and not greater than "maxv". - * - * @param Value Value to clamp. - * @param minv Minimal allowed value. - * @param maxv Maximal allowed value. - * @return The clamped value. - */ - -inline float8 clamp( const float8& Value, const float8& minv, - const float8& maxv ) -{ - return( _mm256_min_ps( _mm256_max_ps( Value.value, minv.value ), - maxv.value )); -} - -typedef fpclass_def_dil< float, avir :: float8 > fpclass_float8_dil; ///< - ///< Class that can be used as the "fpclass" template parameter of the - ///< avir::CImageResizer class to perform calculation using - ///< de-interleaved SIMD algorithm, using SIMD float8 type. - ///< - -} // namespace avir - -#endif // AVIR_FLOAT8_AVX_INCLUDED diff --git a/Modules/gin/3rdparty/muParser/muParser.cpp b/Modules/gin/3rdparty/muParser/muParser.cpp deleted file mode 100755 index ed22b00..0000000 --- a/Modules/gin/3rdparty/muParser/muParser.cpp +++ /dev/null @@ -1,397 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - - Copyright (C) 2013 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -#include "muParser.h" -#include "muParserTemplateMagic.h" - -//--- Standard includes ------------------------------------------------------------------------ -#include -#include -#include - -/** \brief Pi (what else?). */ -#define PARSER_CONST_PI 3.141592653589793238462643 - -/** \brief The Eulerian number. */ -#define PARSER_CONST_E 2.718281828459045235360287 - -using namespace std; - -/** \file - \brief Implementation of the standard floating point parser. -*/ - - - -/** \brief Namespace for mathematical applications. */ -namespace mu -{ - - - //--------------------------------------------------------------------------- - // Trigonometric function - value_type Parser::Sin(SParam, value_type v) { return MathImpl::Sin(v); } - value_type Parser::Cos(SParam, value_type v) { return MathImpl::Cos(v); } - value_type Parser::Tan(SParam, value_type v) { return MathImpl::Tan(v); } - value_type Parser::ASin(SParam, value_type v) { return MathImpl::ASin(v); } - value_type Parser::ACos(SParam, value_type v) { return MathImpl::ACos(v); } - value_type Parser::ATan(SParam, value_type v) { return MathImpl::ATan(v); } - value_type Parser::ATan2(SParam, value_type v1, value_type v2) { return MathImpl::ATan2(v1, v2); } - value_type Parser::Sinh(SParam, value_type v) { return MathImpl::Sinh(v); } - value_type Parser::Cosh(SParam, value_type v) { return MathImpl::Cosh(v); } - value_type Parser::Tanh(SParam, value_type v) { return MathImpl::Tanh(v); } - value_type Parser::ASinh(SParam, value_type v) { return MathImpl::ASinh(v); } - value_type Parser::ACosh(SParam, value_type v) { return MathImpl::ACosh(v); } - value_type Parser::ATanh(SParam, value_type v) { return MathImpl::ATanh(v); } - - //--------------------------------------------------------------------------- - // Logarithm functions - - // Logarithm base 2 - value_type Parser::Log2(SParam, value_type v) - { - #ifdef MUP_MATH_EXCEPTIONS - if (v<=0) - throw ParserError(ecDOMAIN_ERROR, _T("Log2")); - #endif - - return MathImpl::Log2(v); - } - - // Logarithm base 10 - value_type Parser::Log10(SParam, value_type v) - { - #ifdef MUP_MATH_EXCEPTIONS - if (v<=0) - throw ParserError(ecDOMAIN_ERROR, _T("Log10")); - #endif - - return MathImpl::Log10(v); - } - -// Logarithm base e (natural logarithm) - value_type Parser::Ln(SParam, value_type v) - { - #ifdef MUP_MATH_EXCEPTIONS - if (v<=0) - throw ParserError(ecDOMAIN_ERROR, _T("Ln")); - #endif - - return MathImpl::Log(v); - } - - //--------------------------------------------------------------------------- - // misc - value_type Parser::Exp(SParam, value_type v) { return MathImpl::Exp(v); } - value_type Parser::Abs(SParam, value_type v) { return MathImpl::Abs(v); } - value_type Parser::Sqrt(SParam, value_type v) - { - #ifdef MUP_MATH_EXCEPTIONS - if (v<0) - throw ParserError(ecDOMAIN_ERROR, _T("sqrt")); - #endif - - return MathImpl::Sqrt(v); - } - value_type Parser::Rint(SParam, value_type v) { return MathImpl::Rint(v); } - value_type Parser::Sign(SParam, value_type v) { return MathImpl::Sign(v); } - - //--------------------------------------------------------------------------- - /** \brief Callback for the unary minus operator. - \param v The value to negate - \return -v - */ - value_type Parser::UnaryMinus(SParam, value_type v) - { - return -v; - } - - //--------------------------------------------------------------------------- - /** \brief Callback for the unary minus operator. - \param v The value to negate - \return -v - */ - value_type Parser::UnaryPlus(SParam, value_type v) - { - return v; - } - - //--------------------------------------------------------------------------- - /** \brief Callback for adding multiple values. - \param [in] a_afArg Vector with the function arguments - \param [in] a_iArgc The size of a_afArg - */ - value_type Parser::Sum(SParam, const value_type *a_afArg, int a_iArgc) - { - if (!a_iArgc) - throw exception_type(_T("too few arguments for function sum.")); - - value_type fRes=0; - for (int i=0; i> fVal; - stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading - - if (iEnd==(stringstream_type::pos_type)-1) - return 0; - - *a_iPos += (int)iEnd; - *a_fVal = fVal; - return 1; - } - - - //--------------------------------------------------------------------------- - /** \brief Constructor. - - Call ParserBase class constructor and trigger Function, Operator and Constant initialization. - */ - Parser::Parser() - :ParserBase() - { - AddValIdent(IsVal); - - InitCharSets(); - InitFun(); - InitConst(); - InitOprt(); - } - - //--------------------------------------------------------------------------- - /** \brief Define the character sets. - \sa DefineNameChars, DefineOprtChars, DefineInfixOprtChars - - This function is used for initializing the default character sets that define - the characters to be useable in function and variable names and operators. - */ - void Parser::InitCharSets() - { - DefineNameChars( _T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") ); - DefineOprtChars( _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_{}") ); - DefineInfixOprtChars( _T("/+-*^?<>=#!$%&|~'_") ); - } - - //--------------------------------------------------------------------------- - /** \brief Initialize the default functions. */ - void Parser::InitFun() - { - if (mu::TypeInfo::IsInteger()) - { - // When setting MUP_BASETYPE to an integer type - // Place functions for dealing with integer values here - // ... - // ... - // ... - } - else - { - // trigonometric functions - DefineFun(_T("sin"), Sin); - DefineFun(_T("cos"), Cos); - DefineFun(_T("tan"), Tan); - // arcus functions - DefineFun(_T("asin"), ASin); - DefineFun(_T("acos"), ACos); - DefineFun(_T("atan"), ATan); - DefineFun(_T("atan2"), ATan2); - // hyperbolic functions - DefineFun(_T("sinh"), Sinh); - DefineFun(_T("cosh"), Cosh); - DefineFun(_T("tanh"), Tanh); - // arcus hyperbolic functions - DefineFun(_T("asinh"), ASinh); - DefineFun(_T("acosh"), ACosh); - DefineFun(_T("atanh"), ATanh); - // Logarithm functions - DefineFun(_T("log2"), Log2); - DefineFun(_T("log10"), Log10); - DefineFun(_T("log"), Ln); - DefineFun(_T("ln"), Ln); - // misc - DefineFun(_T("exp"), Exp); - DefineFun(_T("sqrt"), Sqrt); - DefineFun(_T("sign"), Sign); - DefineFun(_T("rint"), Rint); - DefineFun(_T("abs"), Abs); - // Functions with variable number of arguments - DefineFun(_T("sum"), Sum); - DefineFun(_T("avg"), Avg); - DefineFun(_T("min"), Min); - DefineFun(_T("max"), Max); - } - } - - //--------------------------------------------------------------------------- - /** \brief Initialize constants. - - By default the parser recognizes two constants. Pi ("pi") and the Eulerian - number ("_e"). - */ - void Parser::InitConst() - { - DefineConst(_T("_pi"), (value_type)PARSER_CONST_PI); - DefineConst(_T("_e"), (value_type)PARSER_CONST_E); - } - - //--------------------------------------------------------------------------- - /** \brief Initialize operators. - - By default only the unary minus operator is added. - */ - void Parser::InitOprt() - { - DefineInfixOprt(_T("-"), UnaryMinus); - DefineInfixOprt(_T("+"), UnaryPlus); - } - - //--------------------------------------------------------------------------- - void Parser::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/) - { - // this is just sample code to illustrate modifying variable names on the fly. - // I'm not sure anyone really needs such a feature... - /* - - - string sVar(pExpr->begin()+nStart, pExpr->begin()+nEnd); - string sRepl = std::string("_") + sVar + "_"; - - int nOrigVarEnd = nEnd; - cout << "variable detected!\n"; - cout << " Expr: " << *pExpr << "\n"; - cout << " Start: " << nStart << "\n"; - cout << " End: " << nEnd << "\n"; - cout << " Var: \"" << sVar << "\"\n"; - cout << " Repl: \"" << sRepl << "\"\n"; - nEnd = nStart + sRepl.length(); - cout << " End: " << nEnd << "\n"; - pExpr->replace(pExpr->begin()+nStart, pExpr->begin()+nOrigVarEnd, sRepl); - cout << " New expr: " << *pExpr << "\n"; - */ - } - - //--------------------------------------------------------------------------- - /** \brief Numerically differentiate with regard to a variable. - \param [in] a_Var Pointer to the differentiation variable. - \param [in] a_fPos Position at which the differentiation should take place. - \param [in] a_fEpsilon Epsilon used for the numerical differentiation. - - Numerical differentiation uses a 5 point operator yielding a 4th order - formula. The default value for epsilon is 0.00074 which is - numeric_limits::epsilon() ^ (1/5) as suggested in the muparser - forum: - - http://sourceforge.net/forum/forum.php?thread_id=1994611&forum_id=462843 - */ - value_type Parser::Diff(value_type *a_Var, - value_type a_fPos, - value_type a_fEpsilon) const - { - value_type fRes(0), - fBuf(*a_Var), - f[4] = {0,0,0,0}, - fEpsilon(a_fEpsilon); - - // Backwards compatible calculation of epsilon inc case the user doesn't provide - // his own epsilon - if (fEpsilon==0) - fEpsilon = (a_fPos==0) ? (value_type)1e-10 : (value_type)1e-7 * a_fPos; - - *a_Var = a_fPos+2 * fEpsilon; f[0] = Eval(); - *a_Var = a_fPos+1 * fEpsilon; f[1] = Eval(); - *a_Var = a_fPos-1 * fEpsilon; f[2] = Eval(); - *a_Var = a_fPos-2 * fEpsilon; f[3] = Eval(); - *a_Var = fBuf; // restore variable - - fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon); - return fRes; - } -} // namespace mu diff --git a/Modules/gin/3rdparty/muParser/muParser.h b/Modules/gin/3rdparty/muParser/muParser.h deleted file mode 100755 index 2908e9d..0000000 --- a/Modules/gin/3rdparty/muParser/muParser.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2013 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -#ifndef MU_PARSER_H -#define MU_PARSER_H - -//--- Standard includes ------------------------------------------------------------------------ -#include - -//--- Parser includes -------------------------------------------------------------------------- -#include "muParserBase.h" -#include "muParserTemplateMagic.h" - -/** \file - \brief Definition of the standard floating point parser. -*/ - -namespace mu -{ - /** \brief Mathematical expressions parser. - - Standard implementation of the mathematical expressions parser. - Can be used as a reference implementation for subclassing the parser. - - - (C) 2011 Ingo Berg
- muparser(at)beltoforion.de -
- */ - /* final */ class Parser : public ParserBase - { - public: - - Parser(); - - virtual void InitCharSets(); - virtual void InitFun(); - virtual void InitConst(); - virtual void InitOprt(); - virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd); - - value_type Diff(value_type *a_Var, - value_type a_fPos, - value_type a_fEpsilon = 0) const; - - protected: - - // Trigonometric functions - static value_type Sin(SParam, value_type); - static value_type Cos(SParam, value_type); - static value_type Tan(SParam, value_type); - static value_type Tan2(SParam, value_type, value_type); - // arcus functions - static value_type ASin(SParam, value_type); - static value_type ACos(SParam, value_type); - static value_type ATan(SParam, value_type); - static value_type ATan2(SParam, value_type, value_type); - - // hyperbolic functions - static value_type Sinh(SParam, value_type); - static value_type Cosh(SParam, value_type); - static value_type Tanh(SParam, value_type); - // arcus hyperbolic functions - static value_type ASinh(SParam, value_type); - static value_type ACosh(SParam, value_type); - static value_type ATanh(SParam, value_type); - // Logarithm functions - static value_type Log2(SParam, value_type); // Logarithm Base 2 - static value_type Log10(SParam, value_type); // Logarithm Base 10 - static value_type Ln(SParam, value_type); // Logarithm Base e (natural logarithm) - // misc - static value_type Exp(SParam, value_type); - static value_type Abs(SParam, value_type); - static value_type Sqrt(SParam, value_type); - static value_type Rint(SParam, value_type); - static value_type Sign(SParam, value_type); - - // Prefix operators - // !!! Unary Minus is a MUST if you want to use negative signs !!! - static value_type UnaryMinus(SParam, value_type); - static value_type UnaryPlus(SParam, value_type); - - // Functions with variable number of arguments - static value_type Sum(SParam, const value_type*, int); // sum - static value_type Avg(SParam, const value_type*, int); // mean value - static value_type Min(SParam, const value_type*, int); // minimum - static value_type Max(SParam, const value_type*, int); // maximum - - static int IsVal(SParam, const char_type* a_szExpr, int *a_iPos, value_type *a_fVal); - }; -} // namespace mu - -#endif diff --git a/Modules/gin/3rdparty/muParser/muParserBase.cpp b/Modules/gin/3rdparty/muParser/muParserBase.cpp deleted file mode 100755 index 9955ec4..0000000 --- a/Modules/gin/3rdparty/muParser/muParserBase.cpp +++ /dev/null @@ -1,1805 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2011 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "muParserBase.h" -#include "muParserTemplateMagic.h" - -//--- Standard includes ------------------------------------------------------------------------ -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef MUP_USE_OPENMP - #include -#endif - -#if __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#endif - -using namespace std; - -/** \file - \brief This file contains the basic implementation of the muparser engine. -*/ - -namespace mu -{ - std::locale ParserBase::s_locale = std::locale(std::locale::classic(), new change_dec_sep('.')); - - bool ParserBase::g_DbgDumpCmdCode = false; - bool ParserBase::g_DbgDumpStack = false; - - //------------------------------------------------------------------------------ - /** \brief Identifiers for built in binary operators. - - When defining custom binary operators with #AddOprt(...) make sure not to choose - names conflicting with these definitions. - */ - const char_type* ParserBase::c_DefaultOprt[] = - { - _T("<="), _T(">="), _T("!="), - _T("=="), _T("<"), _T(">"), - _T("+"), _T("-"), _T("*"), - _T("/"), _T("^"), _T("&&"), - _T("||"), _T("="), _T("("), - _T(")"), _T("?"), _T(":"), nullptr - }; - - const int ParserBase::s_MaxNumOpenMPThreads = 16; - - //------------------------------------------------------------------------------ - /** \brief Constructor. - \param a_szFormula the formula to interpret. - \throw ParserException if a_szFormula is null. - */ - ParserBase::ParserBase() - :m_pParseFormula(&ParserBase::ParseString) - ,m_vRPN() - ,m_vStringBuf() - ,m_pTokenReader() - ,m_FunDef() - ,m_PostOprtDef() - ,m_InfixOprtDef() - ,m_OprtDef() - ,m_ConstDef() - ,m_StrVarDef() - ,m_VarDef() - ,m_bBuiltInOp(true) - ,m_sNameChars() - ,m_sOprtChars() - ,m_sInfixOprtChars() - ,m_nIfElseCounter(0) - ,m_vStackBuffer() - ,m_nFinalResultIdx(0) - { - InitTokenReader(); - } - - //--------------------------------------------------------------------------- - /** \brief Copy constructor. - - The parser can be safely copy constructed but the bytecode is reset during - copy construction. - */ - ParserBase::ParserBase(const ParserBase &a_Parser) - :m_pParseFormula(&ParserBase::ParseString) - ,m_vRPN() - ,m_vStringBuf() - ,m_pTokenReader() - ,m_FunDef() - ,m_PostOprtDef() - ,m_InfixOprtDef() - ,m_OprtDef() - ,m_ConstDef() - ,m_StrVarDef() - ,m_VarDef() - ,m_bBuiltInOp(true) - ,m_sNameChars() - ,m_sOprtChars() - ,m_sInfixOprtChars() - ,m_nIfElseCounter(0) - { - m_pTokenReader.reset(new token_reader_type(this)); - Assign(a_Parser); - } - - //--------------------------------------------------------------------------- - ParserBase::~ParserBase() - {} - - //--------------------------------------------------------------------------- - /** \brief Assignment operator. - - Implemented by calling Assign(a_Parser). Self assignment is suppressed. - \param a_Parser Object to copy to this. - \return *this - \throw nothrow - */ - ParserBase& ParserBase::operator=(const ParserBase &a_Parser) - { - Assign(a_Parser); - return *this; - } - - //--------------------------------------------------------------------------- - /** \brief Copy state of a parser object to this. - - Clears Variables and Functions of this parser. - Copies the states of all internal variables. - Resets parse function to string parse mode. - - \param a_Parser the source object. - */ - void ParserBase::Assign(const ParserBase &a_Parser) - { - if (&a_Parser==this) - return; - - // Don't copy bytecode instead cause the parser to create new bytecode - // by resetting the parse function. - ReInit(); - - m_ConstDef = a_Parser.m_ConstDef; // Copy user define constants - m_VarDef = a_Parser.m_VarDef; // Copy user defined variables - m_bBuiltInOp = a_Parser.m_bBuiltInOp; - m_vStringBuf = a_Parser.m_vStringBuf; - m_vStackBuffer = a_Parser.m_vStackBuffer; - m_nFinalResultIdx = a_Parser.m_nFinalResultIdx; - m_StrVarDef = a_Parser.m_StrVarDef; - m_vStringVarBuf = a_Parser.m_vStringVarBuf; - m_nIfElseCounter = a_Parser.m_nIfElseCounter; - m_pTokenReader.reset(a_Parser.m_pTokenReader->Clone(this)); - - // Copy function and operator callbacks - m_FunDef = a_Parser.m_FunDef; // Copy function definitions - m_PostOprtDef = a_Parser.m_PostOprtDef; // post value unary operators - m_InfixOprtDef = a_Parser.m_InfixOprtDef; // unary operators for infix notation - m_OprtDef = a_Parser.m_OprtDef; // binary operators - - m_sNameChars = a_Parser.m_sNameChars; - m_sOprtChars = a_Parser.m_sOprtChars; - m_sInfixOprtChars = a_Parser.m_sInfixOprtChars; - } - - //--------------------------------------------------------------------------- - /** \brief Set the decimal separator. - \param cDecSep Decimal separator as a character value. - \sa SetThousandsSep - - By default muparser uses the "C" locale. The decimal separator of this - locale is overwritten by the one provided here. - */ - void ParserBase::SetDecSep(char_type cDecSep) - { - char_type cThousandsSep = std::use_facet< change_dec_sep >(s_locale).thousands_sep(); - s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); - } - - //--------------------------------------------------------------------------- - /** \brief Sets the thousands operator. - \param cThousandsSep The thousands separator as a character - \sa SetDecSep - - By default muparser uses the "C" locale. The thousands separator of this - locale is overwritten by the one provided here. - */ - void ParserBase::SetThousandsSep(char_type cThousandsSep) - { - char_type cDecSep = std::use_facet< change_dec_sep >(s_locale).decimal_point(); - s_locale = std::locale(std::locale("C"), new change_dec_sep(cDecSep, cThousandsSep)); - } - - //--------------------------------------------------------------------------- - /** \brief Resets the locale. - - The default locale used "." as decimal separator, no thousands separator and - "," as function argument separator. - */ - void ParserBase::ResetLocale() - { - s_locale = std::locale(std::locale("C"), new change_dec_sep('.')); - SetArgSep(','); - } - - //--------------------------------------------------------------------------- - /** \brief Initialize the token reader. - - Create new token reader object and submit pointers to function, operator, - constant and variable definitions. - - \post m_pTokenReader.get()!=0 - \throw nothrow - */ - void ParserBase::InitTokenReader() - { - m_pTokenReader.reset(new token_reader_type(this)); - } - - //--------------------------------------------------------------------------- - /** \brief Reset parser to string parsing mode and clear internal buffers. - - Clear bytecode, reset the token reader. - \throw nothrow - */ - void ParserBase::ReInit() const - { - m_pParseFormula = &ParserBase::ParseString; - m_vStringBuf.clear(); - m_vRPN.clear(); - m_pTokenReader->ReInit(); - m_nIfElseCounter = 0; - } - - //--------------------------------------------------------------------------- - void ParserBase::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd*/) - {} - - //--------------------------------------------------------------------------- - /** \brief Returns the version of muparser. - \param eInfo A flag indicating whether the full version info should be - returned or not. - - Format is as follows: "MAJOR.MINOR (COMPILER_FLAGS)" The COMPILER_FLAGS - are returned only if eInfo==pviFULL. - */ - string_type ParserBase::GetVersion(EParserVersionInfo eInfo) const - { - stringstream_type ss; - - ss << MUP_VERSION; - - if (eInfo==pviFULL) - { - ss << _T(" (") << MUP_VERSION_DATE; - ss << std::dec << _T("; ") << sizeof(void*)*8 << _T("BIT"); - -#ifdef _DEBUG - ss << _T("; DEBUG"); -#else - ss << _T("; RELEASE"); -#endif - -#ifdef _UNICODE - ss << _T("; UNICODE"); -#else - #ifdef _MBCS - ss << _T("; MBCS"); - #else - ss << _T("; ASCII"); - #endif -#endif - -#ifdef MUP_USE_OPENMP - ss << _T("; OPENMP"); -//#else -// ss << _T("; NO_OPENMP"); -#endif - -#if defined(MUP_MATH_EXCEPTIONS) - ss << _T("; MATHEXC"); -//#else -// ss << _T("; NO_MATHEXC"); -#endif - - ss << _T(")"); - } - - return ss.str(); - } - - //--------------------------------------------------------------------------- - /** \brief Add a value parsing function. - - When parsing an expression muParser tries to detect values in the expression - string using different valident callbacks. Thus it's possible to parse - for hex values, binary values and floating point values. - */ - void ParserBase::AddValIdent(identfun_type a_pCallback) - { - m_pTokenReader->AddValIdent(a_pCallback); - } - - //--------------------------------------------------------------------------- - /** \brief Set a function that can create variable pointer for unknown expression variables. - \param a_pFactory A pointer to the variable factory. - \param pUserData A user defined context pointer. - */ - void ParserBase::SetVarFactory(facfun_type a_pFactory, void *pUserData) - { - m_pTokenReader->SetVarCreator(a_pFactory, pUserData); - } - - //--------------------------------------------------------------------------- - /** \brief Add a function or operator callback to the parser. */ - void ParserBase::AddCallback( const string_type &a_strName, - const ParserCallback &a_Callback, - funmap_type &a_Storage, - const char_type *a_szCharSet ) - { - if (a_Callback.GetAddr()==nullptr) - Error(ecINVALID_FUN_PTR); - - const funmap_type *pFunMap = &a_Storage; - - // Check for conflicting operator or function names - if ( pFunMap!=&m_FunDef && m_FunDef.find(a_strName)!=m_FunDef.end() ) - Error(ecNAME_CONFLICT, -1, a_strName); - - if ( pFunMap!=&m_PostOprtDef && m_PostOprtDef.find(a_strName)!=m_PostOprtDef.end() ) - Error(ecNAME_CONFLICT, -1, a_strName); - - if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_InfixOprtDef.find(a_strName)!=m_InfixOprtDef.end() ) - Error(ecNAME_CONFLICT, -1, a_strName); - - if ( pFunMap!=&m_InfixOprtDef && pFunMap!=&m_OprtDef && m_OprtDef.find(a_strName)!=m_OprtDef.end() ) - Error(ecNAME_CONFLICT, -1, a_strName); - - CheckOprt(a_strName, a_Callback, a_szCharSet); - a_Storage[a_strName] = a_Callback; - ReInit(); - } - - //--------------------------------------------------------------------------- - /** \brief Check if a name contains invalid characters. - - \throw ParserException if the name contains invalid characters. - */ - void ParserBase::CheckOprt(const string_type &a_sName, - const ParserCallback &a_Callback, - const string_type &a_szCharSet) const - { - if ( !a_sName.length() || - (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) || - (a_sName[0]>='0' && a_sName[0]<='9')) - { - switch(a_Callback.GetCode()) - { - case cmOPRT_POSTFIX: Error(ecINVALID_POSTFIX_IDENT, -1, a_sName); break; - case cmOPRT_INFIX: Error(ecINVALID_INFIX_IDENT, -1, a_sName); break; - default: Error(ecINVALID_NAME, -1, a_sName); - } - } - } - - //--------------------------------------------------------------------------- - /** \brief Check if a name contains invalid characters. - - \throw ParserException if the name contains invalid characters. - */ - void ParserBase::CheckName(const string_type &a_sName, - const string_type &a_szCharSet) const - { - if ( !a_sName.length() || - (a_sName.find_first_not_of(a_szCharSet)!=string_type::npos) || - (a_sName[0]>='0' && a_sName[0]<='9')) - { - Error(ecINVALID_NAME); - } - } - - //--------------------------------------------------------------------------- - /** \brief Set the formula. - \param a_strFormula Formula as string_type - \throw ParserException in case of syntax errors. - - Triggers first time calculation thus the creation of the bytecode and - scanning of used variables. - */ - void ParserBase::SetExpr(const string_type &a_sExpr) - { - // Check locale compatibility - std::locale loc; - if (m_pTokenReader->GetArgSep()==std::use_facet >(loc).decimal_point()) - Error(ecLOCALE); - - // 20060222: Bugfix for Borland-Kylix: - // adding a space to the expression will keep Borlands KYLIX from going wild - // when calling tellg on a stringstream created from the expression after - // reading a value at the end of an expression. (mu::Parser::IsVal function) - // (tellg returns -1 otherwise causing the parser to ignore the value) - string_type sBuf(a_sExpr + _T(" ") ); - m_pTokenReader->SetFormula(sBuf); - ReInit(); - } - - //--------------------------------------------------------------------------- - /** \brief Get the default symbols used for the built in operators. - \sa c_DefaultOprt - */ - const char_type** ParserBase::GetOprtDef() const - { - return (const char_type **)(&c_DefaultOprt[0]); - } - - //--------------------------------------------------------------------------- - /** \brief Define the set of valid characters to be used in names of - functions, variables, constants. - */ - void ParserBase::DefineNameChars(const char_type *a_szCharset) - { - m_sNameChars = a_szCharset; - } - - //--------------------------------------------------------------------------- - /** \brief Define the set of valid characters to be used in names of - binary operators and postfix operators. - */ - void ParserBase::DefineOprtChars(const char_type *a_szCharset) - { - m_sOprtChars = a_szCharset; - } - - //--------------------------------------------------------------------------- - /** \brief Define the set of valid characters to be used in names of - infix operators. - */ - void ParserBase::DefineInfixOprtChars(const char_type *a_szCharset) - { - m_sInfixOprtChars = a_szCharset; - } - - //--------------------------------------------------------------------------- - /** \brief Virtual function that defines the characters allowed in name identifiers. - \sa #ValidOprtChars, #ValidPrefixOprtChars - */ - const char_type* ParserBase::ValidNameChars() const - { - assert(m_sNameChars.size()); - return m_sNameChars.c_str(); - } - - //--------------------------------------------------------------------------- - /** \brief Virtual function that defines the characters allowed in operator definitions. - \sa #ValidNameChars, #ValidPrefixOprtChars - */ - const char_type* ParserBase::ValidOprtChars() const - { - assert(m_sOprtChars.size()); - return m_sOprtChars.c_str(); - } - - //--------------------------------------------------------------------------- - /** \brief Virtual function that defines the characters allowed in infix operator definitions. - \sa #ValidNameChars, #ValidOprtChars - */ - const char_type* ParserBase::ValidInfixOprtChars() const - { - assert(m_sInfixOprtChars.size()); - return m_sInfixOprtChars.c_str(); - } - - //--------------------------------------------------------------------------- - /** \brief Add a user defined operator. - \post Will reset the Parser to string parsing mode. - */ - void ParserBase::DefinePostfixOprt(const string_type &a_sName, - fun_type1 a_pFun, - bool a_bAllowOpt) - { - AddCallback(a_sName, - ParserCallback(a_pFun, nullptr, a_bAllowOpt, prPOSTFIX, cmOPRT_POSTFIX), - m_PostOprtDef, - ValidOprtChars() ); - } - - //--------------------------------------------------------------------------- - /** \brief Initialize user defined functions. - - Calls the virtual functions InitFun(), InitConst() and InitOprt(). - */ - void ParserBase::Init() - { - InitCharSets(); - InitFun(); - InitConst(); - InitOprt(); - } - - //--------------------------------------------------------------------------- - /** \brief Add a user defined operator. - \post Will reset the Parser to string parsing mode. - \param [in] a_sName operator Identifier - \param [in] a_pFun Operator callback function - \param [in] a_iPrec Operator Precedence (default=prSIGN) - \param [in] a_bAllowOpt True if operator is volatile (default=false) - \sa EPrec - */ - void ParserBase::DefineInfixOprt(const string_type &a_sName, - fun_type1 a_pFun, - int a_iPrec, - bool a_bAllowOpt) - { - AddCallback(a_sName, - ParserCallback(a_pFun, nullptr, a_bAllowOpt, a_iPrec, cmOPRT_INFIX), - m_InfixOprtDef, - ValidInfixOprtChars() ); - } - - - //--------------------------------------------------------------------------- - /** \brief Define a binary operator. - \param [in] a_sName The identifier of the operator. - \param [in] a_pFun Pointer to the callback function. - \param [in] a_iPrec Precedence of the operator. - \param [in] a_eAssociativity The associativity of the operator. - \param [in] a_bAllowOpt If this is true the operator may be optimized away. - - Adds a new Binary operator the the parser instance. - */ - void ParserBase::DefineOprt( const string_type &a_sName, - fun_type2 a_pFun, - unsigned a_iPrec, - EOprtAssociativity a_eAssociativity, - bool a_bAllowOpt ) - { - // Check for conflicts with built in operator names - for (int i=0; m_bBuiltInOp && iIgnoreUndefVar(true); - CreateRPN(); // try to create bytecode, but don't use it for any further calculations since it - // may contain references to nonexisting variables. - m_pParseFormula = &ParserBase::ParseString; - m_pTokenReader->IgnoreUndefVar(false); - } - catch(exception_type & /*e*/) - { - // Make sure to stay in string parse mode, don't call ReInit() - // because it deletes the array with the used variables - m_pParseFormula = &ParserBase::ParseString; - m_pTokenReader->IgnoreUndefVar(false); - throw; - } - - return m_pTokenReader->GetUsedVar(); - } - - //--------------------------------------------------------------------------- - /** \brief Return a map containing the used variables only. */ - const varmap_type& ParserBase::GetVar() const - { - return m_VarDef; - } - - //--------------------------------------------------------------------------- - /** \brief Return a map containing all parser constants. */ - const valmap_type& ParserBase::GetConst() const - { - return m_ConstDef; - } - - //--------------------------------------------------------------------------- - /** \brief Return prototypes of all parser functions. - \return #m_FunDef - \sa FunProt - \throw nothrow - - The return type is a map of the public type #funmap_type containing the prototype - definitions for all numerical parser functions. String functions are not part of - this map. The Prototype definition is encapsulated in objects of the class FunProt - one per parser function each associated with function names via a map construct. - */ - const funmap_type& ParserBase::GetFunDef() const - { - return m_FunDef; - } - - //--------------------------------------------------------------------------- - /** \brief Retrieve the formula. */ - const string_type& ParserBase::GetExpr() const - { - return m_pTokenReader->GetExpr(); - } - - //--------------------------------------------------------------------------- - /** \brief Execute a function that takes a single string argument. - \param a_FunTok Function token. - \throw exception_type If the function token is not a string function - */ - ParserBase::token_type ParserBase::ApplyStrFunc(const token_type &a_FunTok, - const std::vector &a_vArg) const - { - if (a_vArg.back().GetCode()!=cmSTRING) - Error(ecSTRING_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); - - token_type valTok; - generic_fun_type pFunc = a_FunTok.GetFuncAddr(); - assert(pFunc); - - try - { - // Check function arguments; write dummy value into valtok to represent the result - switch(a_FunTok.GetArgCount()) - { - case 0: valTok.SetVal(1); a_vArg[0].GetAsString(); break; - case 1: valTok.SetVal(1); a_vArg[1].GetAsString(); a_vArg[0].GetVal(); break; - case 2: valTok.SetVal(1); a_vArg[2].GetAsString(); a_vArg[1].GetVal(); a_vArg[0].GetVal(); break; - default: Error(ecINTERNAL_ERROR); - } - } - catch(ParserError& ) - { - Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), a_FunTok.GetAsString()); - } - - // string functions won't be optimized - m_vRPN.AddStrFun(pFunc, a_FunTok.GetParam(), a_FunTok.GetArgCount(), a_vArg.back().GetIdx()); - - // Push dummy value representing the function result to the stack - return valTok; - } - - //--------------------------------------------------------------------------- - /** \brief Apply a function token. - \param iArgCount Number of Arguments actually gathered used only for multiarg functions. - \post The result is pushed to the value stack - \post The function token is removed from the stack - \throw exception_type if Argument count does not match function requirements. - */ - void ParserBase::ApplyFunc( ParserStack &a_stOpt, - ParserStack &a_stVal, - int a_iArgCount) const - { - assert(m_pTokenReader.get()); - - // Operator stack empty or does not contain tokens with callback functions - if (a_stOpt.empty() || a_stOpt.top().GetFuncAddr()==nullptr ) - return; - - token_type funTok = a_stOpt.pop(); - assert(funTok.GetFuncAddr()); - - // Binary operators must rely on their internal operator number - // since counting of operators relies on commas for function arguments - // binary operators do not have commas in their expression - int iArgCount = (funTok.GetCode()==cmOPRT_BIN) ? funTok.GetArgCount() : a_iArgCount; - - // determine how many parameters the function needs. To remember iArgCount includes the - // string parameter whilst GetArgCount() counts only numeric parameters. - int iArgRequired = funTok.GetArgCount() + ((funTok.GetType()==tpSTR) ? 1 : 0); - - // That's the number of numerical parameters - int iArgNumerical = iArgCount - ((funTok.GetType()==tpSTR) ? 1 : 0); - - if (funTok.GetCode()==cmFUNC_STR && iArgCount-iArgNumerical>1) - Error(ecINTERNAL_ERROR); - - if (funTok.GetArgCount()>=0 && iArgCount>iArgRequired) - Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); - - if (funTok.GetCode()!=cmOPRT_BIN && iArgCountGetPos()-1, funTok.GetAsString()); - - if (funTok.GetCode()==cmFUNC_STR && iArgCount>iArgRequired ) - Error(ecTOO_MANY_PARAMS, m_pTokenReader->GetPos()-1, funTok.GetAsString()); - - // Collect the numeric function arguments from the value stack and store them - // in a vector - std::vector stArg; - for (int i=0; iGetPos(), funTok.GetAsString()); - } - - switch(funTok.GetCode()) - { - case cmFUNC_STR: - stArg.push_back(a_stVal.pop()); - - if ( stArg.back().GetType()==tpSTR && funTok.GetType()!=tpSTR ) - Error(ecVAL_EXPECTED, m_pTokenReader->GetPos(), funTok.GetAsString()); - - ApplyStrFunc(funTok, stArg); - break; - - case cmFUNC_BULK: - m_vRPN.AddBulkFun(funTok.GetFuncAddr(), funTok.GetParam(), (int)stArg.size()); - break; - - case cmOPRT_BIN: - case cmOPRT_POSTFIX: - case cmOPRT_INFIX: - case cmFUNC: - if (funTok.GetArgCount()==-1 && iArgCount==0) - Error(ecTOO_FEW_PARAMS, m_pTokenReader->GetPos(), funTok.GetAsString()); - - m_vRPN.AddFun(funTok.GetFuncAddr(), funTok.GetParam(), (funTok.GetArgCount()==-1) ? -iArgNumerical : iArgNumerical); - break; - default: - break; - } - - // Push dummy value representing the function result to the stack - token_type token; - token.SetVal(1); - a_stVal.push(token); - } - - //--------------------------------------------------------------------------- - void ParserBase::ApplyIfElse(ParserStack &a_stOpt, - ParserStack &a_stVal) const - { - // Check if there is an if Else clause to be calculated - while (a_stOpt.size() && a_stOpt.top().GetCode()==cmELSE) - { - token_type opElse = a_stOpt.pop(); - MUP_ASSERT(a_stOpt.size()>0); - - // Take the value associated with the else branch from the value stack - token_type vVal2 = a_stVal.pop(); - - MUP_ASSERT(a_stOpt.size()>0); - MUP_ASSERT(a_stVal.size()>=2); - - // it then else is a ternary operator Pop all three values from the value s - // tack and just return the right value - token_type vVal1 = a_stVal.pop(); - token_type vExpr = a_stVal.pop(); - - a_stVal.push( (vExpr.GetVal()!=0) ? vVal1 : vVal2); - - token_type opIf = a_stOpt.pop(); - MUP_ASSERT(opElse.GetCode()==cmELSE); - MUP_ASSERT(opIf.GetCode()==cmIF); - - m_vRPN.AddIfElse(cmENDIF); - } // while pending if-else-clause found - } - - //--------------------------------------------------------------------------- - /** \brief Performs the necessary steps to write code for - the execution of binary operators into the bytecode. - */ - void ParserBase::ApplyBinOprt(ParserStack &a_stOpt, - ParserStack &a_stVal) const - { - // is it a user defined binary operator? - if (a_stOpt.top().GetCode()==cmOPRT_BIN) - { - ApplyFunc(a_stOpt, a_stVal, 2); - } - else - { - MUP_ASSERT(a_stVal.size()>=2); - token_type valTok1 = a_stVal.pop(), - valTok2 = a_stVal.pop(), - optTok = a_stOpt.pop(), - resTok; - - if ( valTok1.GetType()!=valTok2.GetType() || - (valTok1.GetType()==tpSTR && valTok2.GetType()==tpSTR) ) - Error(ecOPRT_TYPE_CONFLICT, m_pTokenReader->GetPos(), optTok.GetAsString()); - - if (optTok.GetCode()==cmASSIGN) - { - if (valTok2.GetCode()!=cmVAR) - Error(ecUNEXPECTED_OPERATOR, -1, _T("=")); - - m_vRPN.AddAssignOp(valTok2.GetVar()); - } - else - m_vRPN.AddOp(optTok.GetCode()); - - resTok.SetVal(1); - a_stVal.push(resTok); - } - } - - //--------------------------------------------------------------------------- - /** \brief Apply a binary operator. - \param a_stOpt The operator stack - \param a_stVal The value stack - */ - void ParserBase::ApplyRemainingOprt(ParserStack &stOpt, - ParserStack &stVal) const - { - while (stOpt.size() && - stOpt.top().GetCode() != cmBO && - stOpt.top().GetCode() != cmIF) - { - token_type tok = stOpt.top(); - switch (tok.GetCode()) - { - case cmOPRT_INFIX: - case cmOPRT_BIN: - case cmLE: - case cmGE: - case cmNEQ: - case cmEQ: - case cmLT: - case cmGT: - case cmADD: - case cmSUB: - case cmMUL: - case cmDIV: - case cmPOW: - case cmLAND: - case cmLOR: - case cmASSIGN: - if (stOpt.top().GetCode()==cmOPRT_INFIX) - ApplyFunc(stOpt, stVal, 1); - else - ApplyBinOprt(stOpt, stVal); - break; - - case cmELSE: - ApplyIfElse(stOpt, stVal); - break; - - default: - Error(ecINTERNAL_ERROR); - } - } - } - - //--------------------------------------------------------------------------- - /** \brief Parse the command code. - \sa ParseString(...) - - Command code contains precalculated stack positions of the values and the - associated operators. The Stack is filled beginning from index one the - value at index zero is not used at all. - */ - value_type ParserBase::ParseCmdCode() const - { - return ParseCmdCodeBulk(0, 0); - } - - //--------------------------------------------------------------------------- - /** \brief Evaluate the RPN. - \param nOffset The offset added to variable addresses (for bulk mode) - \param nThreadID OpenMP Thread id of the calling thread - */ - value_type ParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const - { - assert(nThreadID<=s_MaxNumOpenMPThreads); - - // Note: The check for nOffset==0 and nThreadID here is not necessary but - // brings a minor performance gain when not in bulk mode. - value_type *Stack = ((nOffset==0) && (nThreadID==0)) ? &m_vStackBuffer[0] : &m_vStackBuffer[nThreadID * (m_vStackBuffer.size() / s_MaxNumOpenMPThreads)]; - value_type buf; - int sidx(0); - for (const SToken *pTok = m_vRPN.GetBase(); pTok->Cmd!=cmEND ; ++pTok) - { - switch (pTok->Cmd) - { - // built in binary operators - case cmLE: --sidx; Stack[sidx] = Stack[sidx] <= Stack[sidx+1]; continue; - case cmGE: --sidx; Stack[sidx] = Stack[sidx] >= Stack[sidx+1]; continue; - case cmNEQ: --sidx; Stack[sidx] = Stack[sidx] != Stack[sidx+1]; continue; - case cmEQ: --sidx; Stack[sidx] = Stack[sidx] == Stack[sidx+1]; continue; - case cmLT: --sidx; Stack[sidx] = Stack[sidx] < Stack[sidx+1]; continue; - case cmGT: --sidx; Stack[sidx] = Stack[sidx] > Stack[sidx+1]; continue; - case cmADD: --sidx; Stack[sidx] += Stack[1+sidx]; continue; - case cmSUB: --sidx; Stack[sidx] -= Stack[1+sidx]; continue; - case cmMUL: --sidx; Stack[sidx] *= Stack[1+sidx]; continue; - case cmDIV: --sidx; - - #if defined(MUP_MATH_EXCEPTIONS) - if (Stack[1+sidx]==0) - Error(ecDIV_BY_ZERO); - #endif - Stack[sidx] /= Stack[1+sidx]; - continue; - - case cmPOW: - --sidx; Stack[sidx] = MathImpl::Pow(Stack[sidx], Stack[1+sidx]); - continue; - - case cmLAND: --sidx; Stack[sidx] = Stack[sidx] && Stack[sidx+1]; continue; - case cmLOR: --sidx; Stack[sidx] = Stack[sidx] || Stack[sidx+1]; continue; - - case cmASSIGN: - // Bugfix for Bulkmode: - // for details see: - // https://groups.google.com/forum/embed/?place=forum/muparser-dev&showsearch=true&showpopout=true&showtabs=false&parenturl=http://muparser.beltoforion.de/mup_forum.html&afterlogin&pli=1#!topic/muparser-dev/szgatgoHTws - --sidx; Stack[sidx] = *(pTok->Oprt.ptr + nOffset) = Stack[sidx + 1]; continue; - // original code: - //--sidx; Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1]; continue; - - //case cmBO: // unused, listed for compiler optimization purposes - //case cmBC: - // MUP_FAIL(INVALID_CODE_IN_BYTECODE); - // continue; - - case cmIF: - if (Stack[sidx--]==0) - pTok += pTok->Oprt.offset; - continue; - - case cmELSE: - pTok += pTok->Oprt.offset; - continue; - - case cmENDIF: - continue; - - //case cmARG_SEP: - // MUP_FAIL(INVALID_CODE_IN_BYTECODE); - // continue; - - // value and variable tokens - case cmVAR: Stack[++sidx] = *(pTok->Val.ptr + nOffset); continue; - case cmVAL: Stack[++sidx] = pTok->Val.data2; continue; - - case cmVARPOW2: buf = *(pTok->Val.ptr + nOffset); - Stack[++sidx] = buf*buf; - continue; - - case cmVARPOW3: buf = *(pTok->Val.ptr + nOffset); - Stack[++sidx] = buf*buf*buf; - continue; - - case cmVARPOW4: buf = *(pTok->Val.ptr + nOffset); - Stack[++sidx] = buf*buf*buf*buf; - continue; - - case cmVARMUL: Stack[++sidx] = *(pTok->Val.ptr + nOffset) * pTok->Val.data + pTok->Val.data2; - continue; - - // Next is treatment of numeric functions - case cmFUNC: - { - int iArgCount = pTok->Fun.argc; - - SParam p; - p.id = pTok->Fun.id; - p.param = pTok->Fun.param; - - // switch according to argument count - switch(iArgCount) - { - case 0: sidx += 1; Stack[sidx] = (*(fun_type0)pTok->Fun.ptr)(p); continue; - case 1: Stack[sidx] = (*(fun_type1)pTok->Fun.ptr)(p, Stack[sidx]); continue; - case 2: sidx -= 1; Stack[sidx] = (*(fun_type2)pTok->Fun.ptr)(p, Stack[sidx], Stack[sidx+1]); continue; - case 3: sidx -= 2; Stack[sidx] = (*(fun_type3)pTok->Fun.ptr)(p, Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue; - case 4: sidx -= 3; Stack[sidx] = (*(fun_type4)pTok->Fun.ptr)(p, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue; - case 5: sidx -= 4; Stack[sidx] = (*(fun_type5)pTok->Fun.ptr)(p, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); continue; - case 6: sidx -= 5; Stack[sidx] = (*(fun_type6)pTok->Fun.ptr)(p, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); continue; - case 7: sidx -= 6; Stack[sidx] = (*(fun_type7)pTok->Fun.ptr)(p, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); continue; - case 8: sidx -= 7; Stack[sidx] = (*(fun_type8)pTok->Fun.ptr)(p, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]); continue; - case 9: sidx -= 8; Stack[sidx] = (*(fun_type9)pTok->Fun.ptr)(p, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]); continue; - case 10:sidx -= 9; Stack[sidx] = (*(fun_type10)pTok->Fun.ptr)(p, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]); continue; - default: - if (iArgCount>0) // function with variable arguments store the number as a negative value - Error(ecINTERNAL_ERROR, 1); - - sidx -= -iArgCount - 1; - Stack[sidx] =(*(multfun_type)pTok->Fun.ptr)(p, &Stack[sidx], -iArgCount); - continue; - } - } - - // Next is treatment of string functions - case cmFUNC_STR: - { - sidx -= pTok->Fun.argc -1; - - // The index of the string argument in the string table - int iIdxStack = pTok->Fun.idx; - MUP_ASSERT( iIdxStack>=0 && iIdxStack<(int)m_vStringBuf.size() ); - - SParam p; - p.id = pTok->Fun.id; - p.param = pTok->Fun.param; - - switch(pTok->Fun.argc) // switch according to argument count - { - case 0: Stack[sidx] = (*(strfun_type1)pTok->Fun.ptr)(p, m_vStringBuf[iIdxStack].c_str()); continue; - case 1: Stack[sidx] = (*(strfun_type2)pTok->Fun.ptr)(p, m_vStringBuf[iIdxStack].c_str(), Stack[sidx]); continue; - case 2: Stack[sidx] = (*(strfun_type3)pTok->Fun.ptr)(p, m_vStringBuf[iIdxStack].c_str(), Stack[sidx], Stack[sidx+1]); continue; - } - - continue; - } - - case cmFUNC_BULK: - { - int iArgCount = pTok->Fun.argc; - - SParam p; - p.id = pTok->Fun.id; - p.param = pTok->Fun.param; - - // switch according to argument count - switch(iArgCount) - { - case 0: sidx += 1; Stack[sidx] = (*(bulkfun_type0 )pTok->Fun.ptr)(p, nOffset, nThreadID); continue; - case 1: Stack[sidx] = (*(bulkfun_type1 )pTok->Fun.ptr)(p, nOffset, nThreadID, Stack[sidx]); continue; - case 2: sidx -= 1; Stack[sidx] = (*(bulkfun_type2 )pTok->Fun.ptr)(p, nOffset, nThreadID, Stack[sidx], Stack[sidx+1]); continue; - case 3: sidx -= 2; Stack[sidx] = (*(bulkfun_type3 )pTok->Fun.ptr)(p, nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2]); continue; - case 4: sidx -= 3; Stack[sidx] = (*(bulkfun_type4 )pTok->Fun.ptr)(p, nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3]); continue; - case 5: sidx -= 4; Stack[sidx] = (*(bulkfun_type5 )pTok->Fun.ptr)(p, nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4]); continue; - case 6: sidx -= 5; Stack[sidx] = (*(bulkfun_type6 )pTok->Fun.ptr)(p, nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5]); continue; - case 7: sidx -= 6; Stack[sidx] = (*(bulkfun_type7 )pTok->Fun.ptr)(p, nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6]); continue; - case 8: sidx -= 7; Stack[sidx] = (*(bulkfun_type8 )pTok->Fun.ptr)(p, nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7]); continue; - case 9: sidx -= 8; Stack[sidx] = (*(bulkfun_type9 )pTok->Fun.ptr)(p, nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8]); continue; - case 10:sidx -= 9; Stack[sidx] = (*(bulkfun_type10)pTok->Fun.ptr)(p, nOffset, nThreadID, Stack[sidx], Stack[sidx+1], Stack[sidx+2], Stack[sidx+3], Stack[sidx+4], Stack[sidx+5], Stack[sidx+6], Stack[sidx+7], Stack[sidx+8], Stack[sidx+9]); continue; - default: - Error(ecINTERNAL_ERROR, 2); - continue; - } - } - - default: - Error(ecINTERNAL_ERROR, 3); - return 0; - } // switch CmdCode - } // for all bytecode tokens - - return Stack[m_nFinalResultIdx]; - } - - //--------------------------------------------------------------------------- - void ParserBase::CreateRPN() const - { - if (!m_pTokenReader->GetExpr().length()) - Error(ecUNEXPECTED_EOF, 0); - - ParserStack stOpt, stVal; - ParserStack stArgCount; - token_type opta, opt; // for storing operators - token_type val, tval; // for storing value - - ReInit(); - - // The outermost counter counts the number of separated items - // such as in "a=10,b=20,c=c+a" - stArgCount.push(1); - - for(;;) - { - opt = m_pTokenReader->ReadNextToken(); - - switch (opt.GetCode()) - { - // - // Next three are different kind of value entries - // - case cmSTRING: - opt.SetIdx((int)m_vStringBuf.size()); // Assign buffer index to token - stVal.push(opt); - m_vStringBuf.push_back(opt.GetAsString()); // Store string in internal buffer - break; - - case cmVAR: - stVal.push(opt); - m_vRPN.AddVar( static_cast(opt.GetVar()) ); - break; - - case cmVAL: - stVal.push(opt); - m_vRPN.AddVal( opt.GetVal() ); - break; - - case cmELSE: - m_nIfElseCounter--; - if (m_nIfElseCounter<0) - Error(ecMISPLACED_COLON, m_pTokenReader->GetPos()); - - ApplyRemainingOprt(stOpt, stVal); - m_vRPN.AddIfElse(cmELSE); - stOpt.push(opt); - break; - - - case cmARG_SEP: - if (stArgCount.empty()) - Error(ecUNEXPECTED_ARG_SEP, m_pTokenReader->GetPos()); - - ++stArgCount.top(); - // Falls through. - // intentional (no break!) - - case cmEND: - ApplyRemainingOprt(stOpt, stVal); - break; - - case cmBC: - { - // The argument count for parameterless functions is zero - // by default an opening bracket sets parameter count to 1 - // in preparation of arguments to come. If the last token - // was an opening bracket we know better... - if (opta.GetCode()==cmBO) - --stArgCount.top(); - - ApplyRemainingOprt(stOpt, stVal); - - // Check if the bracket content has been evaluated completely - if (stOpt.size() && stOpt.top().GetCode()==cmBO) - { - // if opt is ")" and opta is "(" the bracket has been evaluated, now its time to check - // if there is either a function or a sign pending - // neither the opening nor the closing bracket will be pushed back to - // the operator stack - // Check if a function is standing in front of the opening bracket, - // if yes evaluate it afterwards check for infix operators - assert(stArgCount.size()); - int iArgCount = stArgCount.pop(); - - stOpt.pop(); // Take opening bracket from stack - - if (iArgCount>1 && ( stOpt.size()==0 || - (stOpt.top().GetCode()!=cmFUNC && - stOpt.top().GetCode()!=cmFUNC_BULK && - stOpt.top().GetCode()!=cmFUNC_STR) ) ) - Error(ecUNEXPECTED_ARG, m_pTokenReader->GetPos()); - - // The opening bracket was popped from the stack now check if there - // was a function before this bracket - if (stOpt.size() && - stOpt.top().GetCode()!=cmOPRT_INFIX && - stOpt.top().GetCode()!=cmOPRT_BIN && - stOpt.top().GetFuncAddr()!=nullptr) - { - ApplyFunc(stOpt, stVal, iArgCount); - } - } - } // if bracket content is evaluated - break; - - // - // Next are the binary operator entries - // - //case cmAND: // built in binary operators - //case cmOR: - //case cmXOR: - case cmIF: - m_nIfElseCounter++; - // Falls through. - // intentional (no break!) - - case cmLAND: - case cmLOR: - case cmLT: - case cmGT: - case cmLE: - case cmGE: - case cmNEQ: - case cmEQ: - case cmADD: - case cmSUB: - case cmMUL: - case cmDIV: - case cmPOW: - case cmASSIGN: - case cmOPRT_BIN: - - // A binary operator (user defined or built in) has been found. - while ( stOpt.size() && - stOpt.top().GetCode() != cmBO && - stOpt.top().GetCode() != cmELSE && - stOpt.top().GetCode() != cmIF) - { - int nPrec1 = GetOprtPrecedence(stOpt.top()), - nPrec2 = GetOprtPrecedence(opt); - - if (stOpt.top().GetCode()==opt.GetCode()) - { - - // Deal with operator associativity - EOprtAssociativity eOprtAsct = GetOprtAssociativity(opt); - if ( (eOprtAsct==oaRIGHT && (nPrec1 <= nPrec2)) || - (eOprtAsct==oaLEFT && (nPrec1 < nPrec2)) ) - { - break; - } - } - else if (nPrec1 < nPrec2) - { - // In case the operators are not equal the precedence decides alone... - break; - } - - if (stOpt.top().GetCode()==cmOPRT_INFIX) - ApplyFunc(stOpt, stVal, 1); - else - ApplyBinOprt(stOpt, stVal); - } // while ( ... ) - - if (opt.GetCode()==cmIF) - m_vRPN.AddIfElse(opt.GetCode()); - - // The operator can't be evaluated right now, push back to the operator stack - stOpt.push(opt); - break; - - // - // Last section contains functions and operators implicitly mapped to functions - // - case cmBO: - stArgCount.push(1); - stOpt.push(opt); - break; - - case cmOPRT_INFIX: - case cmFUNC: - case cmFUNC_BULK: - case cmFUNC_STR: - stOpt.push(opt); - break; - - case cmOPRT_POSTFIX: - stOpt.push(opt); - ApplyFunc(stOpt, stVal, 1); // this is the postfix operator - break; - - default: Error(ecINTERNAL_ERROR, 3); - } // end of switch operator-token - - opta = opt; - - if ( opt.GetCode() == cmEND ) - { - m_vRPN.Finalize(); - break; - } - - if (ParserBase::g_DbgDumpStack) - { - StackDump(stVal, stOpt); - m_vRPN.AsciiDump(); - } - } // while (true) - - if (ParserBase::g_DbgDumpCmdCode) - m_vRPN.AsciiDump(); - - if (m_nIfElseCounter>0) - Error(ecMISSING_ELSE_CLAUSE); - - // get the last value (= final result) from the stack - MUP_ASSERT(stArgCount.size()==1); - m_nFinalResultIdx = stArgCount.top(); - if (m_nFinalResultIdx==0) - Error(ecINTERNAL_ERROR, 9); - - if (stVal.size()==0) - Error(ecEMPTY_EXPRESSION); - - if (stVal.top().GetType()!=tpDBL) - Error(ecSTR_RESULT); - - m_vStackBuffer.resize(m_vRPN.GetMaxStackSize() * s_MaxNumOpenMPThreads); - } - - //--------------------------------------------------------------------------- - /** \brief One of the two main parse functions. - \sa ParseCmdCode(...) - - Parse expression from input string. Perform syntax checking and create - bytecode. After parsing the string and creating the bytecode the function - pointer #m_pParseFormula will be changed to the second parse routine the - uses bytecode instead of string parsing. - */ - value_type ParserBase::ParseString() const - { - try - { - CreateRPN(); - m_pParseFormula = &ParserBase::ParseCmdCode; - return (this->*m_pParseFormula)(); - } - catch(ParserError &exc) - { - exc.SetFormula(m_pTokenReader->GetExpr()); - throw; - } - } - - //--------------------------------------------------------------------------- - /** \brief Create an error containing the parse error position. - - This function will create an Parser Exception object containing the error text and - its position. - - \param a_iErrc [in] The error code of type #EErrorCodes. - \param a_iPos [in] The position where the error was detected. - \param a_strTok [in] The token string representation associated with the error. - \throw ParserException always throws that's the only purpose of this function. - */ - void ParserBase::Error(EErrorCodes a_iErrc, int a_iPos, const string_type &a_sTok) const - { - throw exception_type(a_iErrc, a_sTok, m_pTokenReader->GetExpr(), a_iPos); - } - - //------------------------------------------------------------------------------ - /** \brief Clear all user defined variables. - \throw nothrow - - Resets the parser to string parsing mode by calling #ReInit. - */ - void ParserBase::ClearVar() - { - m_VarDef.clear(); - ReInit(); - } - - //------------------------------------------------------------------------------ - /** \brief Remove a variable from internal storage. - \throw nothrow - - Removes a variable if it exists. If the Variable does not exist nothing will be done. - */ - void ParserBase::RemoveVar(const string_type &a_strVarName) - { - varmap_type::iterator item = m_VarDef.find(a_strVarName); - if (item!=m_VarDef.end()) - { - m_VarDef.erase(item); - ReInit(); - } - } - - //------------------------------------------------------------------------------ - /** \brief Clear all functions. - \post Resets the parser to string parsing mode. - \throw nothrow - */ - void ParserBase::ClearFun() - { - m_FunDef.clear(); - ReInit(); - } - - //------------------------------------------------------------------------------ - /** \brief Clear all user defined constants. - - Both numeric and string constants will be removed from the internal storage. - \post Resets the parser to string parsing mode. - \throw nothrow - */ - void ParserBase::ClearConst() - { - m_ConstDef.clear(); - m_StrVarDef.clear(); - ReInit(); - } - - //------------------------------------------------------------------------------ - /** \brief Clear all user defined postfix operators. - \post Resets the parser to string parsing mode. - \throw nothrow - */ - void ParserBase::ClearPostfixOprt() - { - m_PostOprtDef.clear(); - ReInit(); - } - - //------------------------------------------------------------------------------ - /** \brief Clear all user defined binary operators. - \post Resets the parser to string parsing mode. - \throw nothrow - */ - void ParserBase::ClearOprt() - { - m_OprtDef.clear(); - ReInit(); - } - - //------------------------------------------------------------------------------ - /** \brief Clear the user defined Prefix operators. - \post Resets the parser to string parser mode. - \throw nothrow - */ - void ParserBase::ClearInfixOprt() - { - m_InfixOprtDef.clear(); - ReInit(); - } - - //------------------------------------------------------------------------------ - /** \brief Enable or disable the formula optimization feature. - \post Resets the parser to string parser mode. - \throw nothrow - */ - void ParserBase::EnableOptimizer(bool a_bIsOn) - { - m_vRPN.EnableOptimizer(a_bIsOn); - ReInit(); - } - - //--------------------------------------------------------------------------- - /** \brief Enable the dumping of bytecode and stack content on the console. - \param bDumpCmd Flag to enable dumping of the current bytecode to the console. - \param bDumpStack Flag to enable dumping of the stack content is written to the console. - - This function is for debug purposes only! - */ - void ParserBase::EnableDebugDump(bool bDumpCmd, bool bDumpStack) - { - ParserBase::g_DbgDumpCmdCode = bDumpCmd; - ParserBase::g_DbgDumpStack = bDumpStack; - } - - //------------------------------------------------------------------------------ - /** \brief Enable or disable the built in binary operators. - \throw nothrow - \sa m_bBuiltInOp, ReInit() - - If you disable the built in binary operators there will be no binary operators - defined. Thus you must add them manually one by one. It is not possible to - disable built in operators selectively. This function will Reinitialize the - parser by calling ReInit(). - */ - void ParserBase::EnableBuiltInOprt(bool a_bIsOn) - { - m_bBuiltInOp = a_bIsOn; - ReInit(); - } - - //------------------------------------------------------------------------------ - /** \brief Query status of built in variables. - \return #m_bBuiltInOp; true if built in operators are enabled. - \throw nothrow - */ - bool ParserBase::HasBuiltInOprt() const - { - return m_bBuiltInOp; - } - - //------------------------------------------------------------------------------ - /** \brief Get the argument separator character. - */ - char_type ParserBase::GetArgSep() const - { - return m_pTokenReader->GetArgSep(); - } - - //------------------------------------------------------------------------------ - /** \brief Set argument separator. - \param cArgSep the argument separator character. - */ - void ParserBase::SetArgSep(char_type cArgSep) - { - m_pTokenReader->SetArgSep(cArgSep); - } - - //------------------------------------------------------------------------------ - /** \brief Dump stack content. - - This function is used for debugging only. - */ - void ParserBase::StackDump(const ParserStack &a_stVal, - const ParserStack &a_stOprt) const - { - ParserStack stOprt(a_stOprt), - stVal(a_stVal); - - mu::console() << _T("\nValue stack:\n"); - while ( !stVal.empty() ) - { - token_type val = stVal.pop(); - if (val.GetType()==tpSTR) - mu::console() << _T(" \"") << val.GetAsString() << _T("\" "); - else - mu::console() << _T(" ") << val.GetVal() << _T(" "); - } - mu::console() << "\nOperator stack:\n"; - - while ( !stOprt.empty() ) - { - if (stOprt.top().GetCode()<=cmASSIGN) - { - mu::console() << _T("OPRT_INTRNL \"") - << ParserBase::c_DefaultOprt[stOprt.top().GetCode()] - << _T("\" \n"); - } - else - { - switch(stOprt.top().GetCode()) - { - case cmVAR: mu::console() << _T("VAR\n"); break; - case cmVAL: mu::console() << _T("VAL\n"); break; - case cmFUNC: mu::console() << _T("FUNC \"") - << stOprt.top().GetAsString() - << _T("\"\n"); break; - case cmFUNC_BULK: mu::console() << _T("FUNC_BULK \"") - << stOprt.top().GetAsString() - << _T("\"\n"); break; - case cmOPRT_INFIX: mu::console() << _T("OPRT_INFIX \"") - << stOprt.top().GetAsString() - << _T("\"\n"); break; - case cmOPRT_BIN: mu::console() << _T("OPRT_BIN \"") - << stOprt.top().GetAsString() - << _T("\"\n"); break; - case cmFUNC_STR: mu::console() << _T("FUNC_STR\n"); break; - case cmEND: mu::console() << _T("END\n"); break; - case cmUNKNOWN: mu::console() << _T("UNKNOWN\n"); break; - case cmBO: mu::console() << _T("BRACKET \"(\"\n"); break; - case cmBC: mu::console() << _T("BRACKET \")\"\n"); break; - case cmIF: mu::console() << _T("IF\n"); break; - case cmELSE: mu::console() << _T("ELSE\n"); break; - case cmENDIF: mu::console() << _T("ENDIF\n"); break; - default: mu::console() << stOprt.top().GetCode() << _T(" "); break; - } - } - stOprt.pop(); - } - - mu::console() << dec << endl; - } - - //------------------------------------------------------------------------------ - /** \brief Evaluate an expression containing comma separated subexpressions - \param [out] nStackSize The total number of results available - \return Pointer to the array containing all expression results - - This member function can be used to retrieve all results of an expression - made up of multiple comma separated subexpressions (i.e. "x+y,sin(x),cos(y)") - */ - value_type* ParserBase::Eval(int &nStackSize) const - { - (this->*m_pParseFormula)(); - nStackSize = m_nFinalResultIdx; - - // (for historic reasons the stack starts at position 1) - return &m_vStackBuffer[1]; - } - - //--------------------------------------------------------------------------- - /** \brief Return the number of results on the calculation stack. - - If the expression contains comma separated subexpressions (i.e. "sin(y), x+y"). - There may be more than one return value. This function returns the number of - available results. - */ - int ParserBase::GetNumResults() const - { - return m_nFinalResultIdx; - } - - //--------------------------------------------------------------------------- - /** \brief Calculate the result. - - A note on const correctness: - I consider it important that Calc is a const function. - Due to caching operations Calc changes only the state of internal variables with one exception - m_UsedVar this is reset during string parsing and accessible from the outside. Instead of making - Calc non const GetUsedVar is non const because it explicitly calls Eval() forcing this update. - - \pre A formula must be set. - \pre Variables must have been set (if needed) - - \sa #m_pParseFormula - \return The evaluation result - \throw ParseException if no Formula is set or in case of any other error related to the formula. - */ - value_type ParserBase::Eval() const - { - return (this->*m_pParseFormula)(); - } - - //--------------------------------------------------------------------------- - void ParserBase::Eval(value_type *results, int nBulkSize) - { -/* Commented because it is making a unit test impossible - - // Parallelization does not make sense for fewer than 10000 computations - // due to thread creation overhead. If the bulk size is below 2000 - // computation is refused. - if (nBulkSize<2000) - { - throw ParserError(ecUNREASONABLE_NUMBER_OF_COMPUTATIONS); - } -*/ - CreateRPN(); - - int i = 0; - -#ifdef MUP_USE_OPENMP -//#define DEBUG_OMP_STUFF - #ifdef DEBUG_OMP_STUFF - int *pThread = new int[nBulkSize]; - int *pIdx = new int[nBulkSize]; - #endif - - int nMaxThreads = std::min(omp_get_max_threads(), s_MaxNumOpenMPThreads); - int nThreadID = 0, ct = 0; - omp_set_num_threads(nMaxThreads); - - #pragma omp parallel for schedule(static, nBulkSize/nMaxThreads) private(nThreadID) - for (i=0; i \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2013 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -#ifndef MU_PARSER_BASE_H -#define MU_PARSER_BASE_H - -//--- Standard includes ------------------------------------------------------------------------ -#include -#include -#include -#include -#include -#include -#include - -//--- Parser includes -------------------------------------------------------------------------- -#include "muParserDef.h" -#include "muParserStack.h" -#include "muParserTokenReader.h" -#include "muParserBytecode.h" -#include "muParserError.h" - -#ifdef _WIN32 -#pragma warning(push) -#pragma warning(disable: 4310) -#endif - -namespace mu -{ -/** \file - \brief This file contains the class definition of the muparser engine. -*/ - -//-------------------------------------------------------------------------------------------------- -/** \brief Mathematical expressions parser (base parser engine). - \author (C) 2013 Ingo Berg - - This is the implementation of a bytecode based mathematical expressions parser. - The formula will be parsed from string and converted into a bytecode. - Future calculations will be done with the bytecode instead the formula string - resulting in a significant performance increase. - Complementary to a set of internally implemented functions the parser is able to handle - user defined functions and variables. -*/ -class ParserBase -{ -friend class ParserTokenReader; - -private: - - /** \brief Typedef for the parse functions. - - The parse function do the actual work. The parser exchanges - the function pointer to the parser function depending on - which state it is in. (i.e. bytecode parser vs. string parser) - */ - typedef value_type (ParserBase::*ParseFunction)() const; - - /** \brief Type used for storing an array of values. */ - typedef std::vector valbuf_type; - - /** \brief Type for a vector of strings. */ - typedef std::vector stringbuf_type; - - /** \brief Typedef for the token reader. */ - typedef ParserTokenReader token_reader_type; - - /** \brief Type used for parser tokens. */ - typedef ParserToken token_type; - - /** \brief Maximum number of threads spawned by OpenMP when using the bulk mode. */ - static const int s_MaxNumOpenMPThreads; - - public: - - /** \brief Type of the error class. - - Included for backwards compatibility. - */ - typedef ParserError exception_type; - - static void EnableDebugDump(bool bDumpCmd, bool bDumpStack); - - ParserBase(); - ParserBase(const ParserBase &a_Parser); - ParserBase& operator=(const ParserBase &a_Parser); - - virtual ~ParserBase(); - - value_type Eval() const; - value_type* Eval(int &nStackSize) const; - void Eval(value_type *results, int nBulkSize); - - int GetNumResults() const; - - void SetExpr(const string_type &a_sExpr); - void SetVarFactory(facfun_type a_pFactory, void *pUserData = nullptr); - - void SetDecSep(char_type cDecSep); - void SetThousandsSep(char_type cThousandsSep = 0); - void ResetLocale(); - - void EnableOptimizer(bool a_bIsOn=true); - void EnableBuiltInOprt(bool a_bIsOn=true); - - bool HasBuiltInOprt() const; - void AddValIdent(identfun_type a_pCallback); - - /** \fn void mu::ParserBase::DefineFun(const string_type &a_strName, fun_type0 a_pFun, bool a_bAllowOpt = true) - \brief Define a parser function without arguments. - \param a_strName Name of the function - \param a_pFun Pointer to the callback function - \param a_bAllowOpt A flag indicating this function may be optimized - */ - template - void DefineFun(const string_type &a_strName, T a_pFun, void* param = nullptr, bool a_bAllowOpt = true) - { - AddCallback( a_strName, ParserCallback(a_pFun, param, a_bAllowOpt), m_FunDef, ValidNameChars() ); - } - - void DefineOprt(const string_type &a_strName, - fun_type2 a_pFun, - unsigned a_iPri=0, - EOprtAssociativity a_eAssociativity = oaLEFT, - bool a_bAllowOpt = false); - void DefineConst(const string_type &a_sName, value_type a_fVal); - void DefineStrConst(const string_type &a_sName, const string_type &a_strVal); - void DefineVar(const string_type &a_sName, value_type *a_fVar); - void DefinePostfixOprt(const string_type &a_strFun, fun_type1 a_pOprt, bool a_bAllowOpt=true); - void DefineInfixOprt(const string_type &a_strName, fun_type1 a_pOprt, int a_iPrec=prINFIX, bool a_bAllowOpt=true); - - // Clear user defined variables, constants or functions - void ClearVar(); - void ClearFun(); - void ClearConst(); - void ClearInfixOprt(); - void ClearPostfixOprt(); - void ClearOprt(); - - void RemoveVar(const string_type &a_strVarName); - const varmap_type& GetUsedVar() const; - const varmap_type& GetVar() const; - const valmap_type& GetConst() const; - const string_type& GetExpr() const; - const funmap_type& GetFunDef() const; - string_type GetVersion(EParserVersionInfo eInfo = pviFULL) const; - - const char_type ** GetOprtDef() const; - void DefineNameChars(const char_type *a_szCharset); - void DefineOprtChars(const char_type *a_szCharset); - void DefineInfixOprtChars(const char_type *a_szCharset); - - const char_type* ValidNameChars() const; - const char_type* ValidOprtChars() const; - const char_type* ValidInfixOprtChars() const; - - void SetArgSep(char_type cArgSep); - char_type GetArgSep() const; - - void Error(EErrorCodes a_iErrc, - int a_iPos = (int)mu::string_type::npos, - const string_type &a_strTok = string_type() ) const; - - protected: - - void Init(); - - virtual void InitCharSets() = 0; - virtual void InitFun() = 0; - virtual void InitConst() = 0; - virtual void InitOprt() = 0; - - virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd); - - static const char_type *c_DefaultOprt[]; - static std::locale s_locale; ///< The locale used by the parser - static bool g_DbgDumpCmdCode; - static bool g_DbgDumpStack; - - /** \brief A facet class used to change decimal and thousands separator. */ - template - class change_dec_sep : public std::numpunct - { - public: - - explicit change_dec_sep(char_type cDecSep, char_type cThousandsSep = 0, int nGroup = 3) - :std::numpunct() - ,m_nGroup(nGroup) - ,m_cDecPoint(cDecSep) - ,m_cThousandsSep(cThousandsSep) - {} - - protected: - - virtual char_type do_decimal_point() const - { - return m_cDecPoint; - } - - virtual char_type do_thousands_sep() const - { - return m_cThousandsSep; - } - - virtual std::string do_grouping() const - { - // fix for issue 4: https://code.google.com/p/muparser/issues/detail?id=4 - // courtesy of Jens Bartsch - // original code: - // return std::string(1, (char)m_nGroup); - // new code: - return std::string(1, (char)(m_cThousandsSep > 0 ? m_nGroup : CHAR_MAX)); - } - - private: - - int m_nGroup; - char_type m_cDecPoint; - char_type m_cThousandsSep; - }; - - private: - - void Assign(const ParserBase &a_Parser); - void InitTokenReader(); - void ReInit() const; - - void AddCallback( const string_type &a_strName, - const ParserCallback &a_Callback, - funmap_type &a_Storage, - const char_type *a_szCharSet ); - - void ApplyRemainingOprt(ParserStack &a_stOpt, - ParserStack &a_stVal) const; - void ApplyBinOprt(ParserStack &a_stOpt, - ParserStack &a_stVal) const; - - void ApplyIfElse(ParserStack &a_stOpt, - ParserStack &a_stVal) const; - - void ApplyFunc(ParserStack &a_stOpt, - ParserStack &a_stVal, - int iArgCount) const; - - token_type ApplyStrFunc(const token_type &a_FunTok, - const std::vector &a_vArg) const; - - int GetOprtPrecedence(const token_type &a_Tok) const; - EOprtAssociativity GetOprtAssociativity(const token_type &a_Tok) const; - - void CreateRPN() const; - - value_type ParseString() const; - value_type ParseCmdCode() const; - value_type ParseCmdCodeBulk(int nOffset, int nThreadID) const; - - void CheckName(const string_type &a_strName, const string_type &a_CharSet) const; - void CheckOprt(const string_type &a_sName, - const ParserCallback &a_Callback, - const string_type &a_szCharSet) const; - - void StackDump(const ParserStack &a_stVal, - const ParserStack &a_stOprt) const; - - /** \brief Pointer to the parser function. - - Eval() calls the function whose address is stored there. - */ - mutable ParseFunction m_pParseFormula; - mutable ParserByteCode m_vRPN; ///< The Bytecode class. - mutable stringbuf_type m_vStringBuf; ///< String buffer, used for storing string function arguments - stringbuf_type m_vStringVarBuf; - - std::unique_ptr m_pTokenReader; ///< Managed pointer to the token reader object. - - funmap_type m_FunDef; ///< Map of function names and pointers. - funmap_type m_PostOprtDef; ///< Postfix operator callbacks - funmap_type m_InfixOprtDef; ///< unary infix operator. - funmap_type m_OprtDef; ///< Binary operator callbacks - valmap_type m_ConstDef; ///< user constants. - strmap_type m_StrVarDef; ///< user defined string constants - varmap_type m_VarDef; ///< user defind variables. - - bool m_bBuiltInOp; ///< Flag that can be used for switching built in operators on and off - - string_type m_sNameChars; ///< Charset for names - string_type m_sOprtChars; ///< Charset for postfix/ binary operator tokens - string_type m_sInfixOprtChars; ///< Charset for infix operator tokens - - mutable int m_nIfElseCounter; ///< Internal counter for keeping track of nested if-then-else clauses - - // items merely used for caching state information - mutable valbuf_type m_vStackBuffer; ///< This is merely a buffer used for the stack in the cmd parsing routine - mutable int m_nFinalResultIdx; -}; - -} // namespace mu - -#ifdef _WIN32 -#pragma warning(pop) -#endif - -#endif diff --git a/Modules/gin/3rdparty/muParser/muParserBytecode.cpp b/Modules/gin/3rdparty/muParser/muParserBytecode.cpp deleted file mode 100755 index e2d0aba..0000000 --- a/Modules/gin/3rdparty/muParser/muParserBytecode.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2011 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "muParserBytecode.h" - -#include -#include -#include -#include -#include -#include - -#include "muParserDef.h" -#include "muParserError.h" -#include "muParserToken.h" -#include "muParserStack.h" -#include "muParserTemplateMagic.h" - -#if __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#endif - -namespace mu -{ - //--------------------------------------------------------------------------- - /** \brief Bytecode default constructor. */ - ParserByteCode::ParserByteCode() - :m_iStackPos(0) - ,m_iMaxStackSize(0) - ,m_vRPN() - ,m_bEnableOptimizer(true) - { - m_vRPN.reserve(50); - } - - //--------------------------------------------------------------------------- - /** \brief Copy constructor. - - Implemented in Terms of Assign(const ParserByteCode &a_ByteCode) - */ - ParserByteCode::ParserByteCode(const ParserByteCode &a_ByteCode) - { - Assign(a_ByteCode); - } - - //--------------------------------------------------------------------------- - /** \brief Assignment operator. - - Implemented in Terms of Assign(const ParserByteCode &a_ByteCode) - */ - ParserByteCode& ParserByteCode::operator=(const ParserByteCode &a_ByteCode) - { - Assign(a_ByteCode); - return *this; - } - - //--------------------------------------------------------------------------- - void ParserByteCode::EnableOptimizer(bool bStat) - { - m_bEnableOptimizer = bStat; - } - - //--------------------------------------------------------------------------- - /** \brief Copy state of another object to this. - - \throw nowthrow - */ - void ParserByteCode::Assign(const ParserByteCode &a_ByteCode) - { - if (this==&a_ByteCode) - return; - - m_iStackPos = a_ByteCode.m_iStackPos; - m_vRPN = a_ByteCode.m_vRPN; - m_iMaxStackSize = a_ByteCode.m_iMaxStackSize; - m_bEnableOptimizer = a_ByteCode.m_bEnableOptimizer; - } - - //--------------------------------------------------------------------------- - /** \brief Add a Variable pointer to bytecode. - \param a_pVar Pointer to be added. - \throw nothrow - */ - void ParserByteCode::AddVar(value_type *a_pVar) - { - ++m_iStackPos; - m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); - - // optimization does not apply - SToken tok; - tok.Cmd = cmVAR; - tok.Val.ptr = a_pVar; - tok.Val.data = 1; - tok.Val.data2 = 0; - m_vRPN.push_back(tok); - } - - //--------------------------------------------------------------------------- - /** \brief Add a Variable pointer to bytecode. - - Value entries in byte code consist of: -
    -
  • value array position of the value
  • -
  • the operator code according to ParserToken::cmVAL
  • -
  • the value stored in #mc_iSizeVal number of bytecode entries.
  • -
- - \param a_pVal Value to be added. - \throw nothrow - */ - void ParserByteCode::AddVal(value_type a_fVal) - { - ++m_iStackPos; - m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); - - // If optimization does not apply - SToken tok; - tok.Cmd = cmVAL; - tok.Val.ptr = nullptr; - tok.Val.data = 0; - tok.Val.data2 = a_fVal; - m_vRPN.push_back(tok); - } - - //--------------------------------------------------------------------------- - void ParserByteCode::ConstantFolding(ECmdCode a_Oprt) - { - std::size_t sz = m_vRPN.size(); - value_type &x = m_vRPN[sz-2].Val.data2, - &y = m_vRPN[sz-1].Val.data2; - switch (a_Oprt) - { - case cmLAND: x = (int)x && (int)y; m_vRPN.pop_back(); break; - case cmLOR: x = (int)x || (int)y; m_vRPN.pop_back(); break; - case cmLT: x = x < y; m_vRPN.pop_back(); break; - case cmGT: x = x > y; m_vRPN.pop_back(); break; - case cmLE: x = x <= y; m_vRPN.pop_back(); break; - case cmGE: x = x >= y; m_vRPN.pop_back(); break; - case cmNEQ: x = x != y; m_vRPN.pop_back(); break; - case cmEQ: x = x == y; m_vRPN.pop_back(); break; - case cmADD: x = x + y; m_vRPN.pop_back(); break; - case cmSUB: x = x - y; m_vRPN.pop_back(); break; - case cmMUL: x = x * y; m_vRPN.pop_back(); break; - case cmDIV: - -#if defined(MUP_MATH_EXCEPTIONS) - if (y==0) - throw ParserError(ecDIV_BY_ZERO, _T("0")); -#endif - - x = x / y; - m_vRPN.pop_back(); - break; - - case cmPOW: x = MathImpl::Pow(x, y); - m_vRPN.pop_back(); - break; - - default: - break; - } // switch opcode - } - - //--------------------------------------------------------------------------- - /** \brief Add an operator identifier to bytecode. - - Operator entries in byte code consist of: -
    -
  • value array position of the result
  • -
  • the operator code according to ParserToken::ECmdCode
  • -
- - \sa ParserToken::ECmdCode - */ - void ParserByteCode::AddOp(ECmdCode a_Oprt) - { - bool bOptimized = false; - - if (m_bEnableOptimizer) - { - std::size_t sz = m_vRPN.size(); - - // Check for foldable constants like: - // cmVAL cmVAL cmADD - // where cmADD can stand fopr any binary operator applied to - // two constant values. - if (sz>=2 && m_vRPN[sz-2].Cmd == cmVAL && m_vRPN[sz-1].Cmd == cmVAL) - { - ConstantFolding(a_Oprt); - bOptimized = true; - } - else - { - switch(a_Oprt) - { - case cmPOW: - // Optimization for polynomials of low order - if (m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-1].Cmd == cmVAL) - { - if (m_vRPN[sz-1].Val.data2==2) - m_vRPN[sz-2].Cmd = cmVARPOW2; - else if (m_vRPN[sz-1].Val.data2==3) - m_vRPN[sz-2].Cmd = cmVARPOW3; - else if (m_vRPN[sz-1].Val.data2==4) - m_vRPN[sz-2].Cmd = cmVARPOW4; - else - break; - - m_vRPN.pop_back(); - bOptimized = true; - } - break; - - case cmSUB: - case cmADD: - // Simple optimization based on pattern recognition for a shitload of different - // bytecode combinations of addition/subtraction - if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) || - (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) || - (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) || - (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) || - (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || - (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || - (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAR && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) || - (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ) - { - assert( (m_vRPN[sz-2].Val.ptr==NULL && m_vRPN[sz-1].Val.ptr!=NULL) || - (m_vRPN[sz-2].Val.ptr!=NULL && m_vRPN[sz-1].Val.ptr==NULL) || - (m_vRPN[sz-2].Val.ptr == m_vRPN[sz-1].Val.ptr) ); - - m_vRPN[sz-2].Cmd = cmVARMUL; - m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); // variable - m_vRPN[sz-2].Val.data2 += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data2; // offset - m_vRPN[sz-2].Val.data += ((a_Oprt==cmSUB) ? -1 : 1) * m_vRPN[sz-1].Val.data; // multiplicand - m_vRPN.pop_back(); - bOptimized = true; - } - break; - - case cmMUL: - if ( (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAL) || - (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVAR) ) - { - m_vRPN[sz-2].Cmd = cmVARMUL; - m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); - m_vRPN[sz-2].Val.data = m_vRPN[sz-2].Val.data2 + m_vRPN[sz-1].Val.data2; - m_vRPN[sz-2].Val.data2 = 0; - m_vRPN.pop_back(); - bOptimized = true; - } - else if ( (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL) || - (m_vRPN[sz-1].Cmd == cmVARMUL && m_vRPN[sz-2].Cmd == cmVAL) ) - { - // Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2 - m_vRPN[sz-2].Cmd = cmVARMUL; - m_vRPN[sz-2].Val.ptr = (value_type*)((long long)(m_vRPN[sz-2].Val.ptr) | (long long)(m_vRPN[sz-1].Val.ptr)); - if (m_vRPN[sz-1].Cmd == cmVAL) - { - m_vRPN[sz-2].Val.data *= m_vRPN[sz-1].Val.data2; - m_vRPN[sz-2].Val.data2 *= m_vRPN[sz-1].Val.data2; - } - else - { - m_vRPN[sz-2].Val.data = m_vRPN[sz-1].Val.data * m_vRPN[sz-2].Val.data2; - m_vRPN[sz-2].Val.data2 = m_vRPN[sz-1].Val.data2 * m_vRPN[sz-2].Val.data2; - } - m_vRPN.pop_back(); - bOptimized = true; - } - else if (m_vRPN[sz-1].Cmd == cmVAR && m_vRPN[sz-2].Cmd == cmVAR && - m_vRPN[sz-1].Val.ptr == m_vRPN[sz-2].Val.ptr) - { - // Optimization: a*a -> a^2 - m_vRPN[sz-2].Cmd = cmVARPOW2; - m_vRPN.pop_back(); - bOptimized = true; - } - break; - - case cmDIV: - if (m_vRPN[sz-1].Cmd == cmVAL && m_vRPN[sz-2].Cmd == cmVARMUL && m_vRPN[sz-1].Val.data2!=0) - { - // Optimization: 4*a/2 -> 2*a - m_vRPN[sz-2].Val.data /= m_vRPN[sz-1].Val.data2; - m_vRPN[sz-2].Val.data2 /= m_vRPN[sz-1].Val.data2; - m_vRPN.pop_back(); - bOptimized = true; - } - break; - default: - // no optimization for other opcodes - break; - } // switch a_Oprt - } - } - - // If optimization can't be applied just write the value - if (!bOptimized) - { - --m_iStackPos; - SToken tok; - tok.Cmd = a_Oprt; - m_vRPN.push_back(tok); - } - } - - //--------------------------------------------------------------------------- - void ParserByteCode::AddIfElse(ECmdCode a_Oprt) - { - SToken tok; - tok.Cmd = a_Oprt; - m_vRPN.push_back(tok); - } - - //--------------------------------------------------------------------------- - /** \brief Add an assignment operator - - Operator entries in byte code consist of: -
    -
  • cmASSIGN code
  • -
  • the pointer of the destination variable
  • -
- - \sa ParserToken::ECmdCode - */ - void ParserByteCode::AddAssignOp(value_type *a_pVar) - { - --m_iStackPos; - - SToken tok; - tok.Cmd = cmASSIGN; - tok.Oprt.ptr = a_pVar; - m_vRPN.push_back(tok); - } - - //--------------------------------------------------------------------------- - /** \brief Add function to bytecode. - - \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. - \param a_pFun Pointer to function callback. - */ - void ParserByteCode::AddFun(generic_fun_type a_pFun, void* p, int a_iArgc) - { - if (a_iArgc>=0) - { - m_iStackPos = m_iStackPos - a_iArgc + 1; - } - else - { - // function with unlimited number of arguments - m_iStackPos = m_iStackPos + a_iArgc + 1; - } - m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); - - SToken tok; - tok.Cmd = cmFUNC; - tok.Fun.argc = a_iArgc; - tok.Fun.ptr = a_pFun; - tok.Fun.param = p; - tok.Fun.id = nextId++; - m_vRPN.push_back(tok); - } - - //--------------------------------------------------------------------------- - /** \brief Add a bulk function to bytecode. - - \param a_iArgc Number of arguments, negative numbers indicate multiarg functions. - \param a_pFun Pointer to function callback. - */ - void ParserByteCode::AddBulkFun(generic_fun_type a_pFun, void* p, int a_iArgc) - { - m_iStackPos = m_iStackPos - a_iArgc + 1; - m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); - - SToken tok; - tok.Cmd = cmFUNC_BULK; - tok.Fun.argc = a_iArgc; - tok.Fun.ptr = a_pFun; - tok.Fun.param = p; - tok.Fun.id = nextId++; - m_vRPN.push_back(tok); - } - - //--------------------------------------------------------------------------- - /** \brief Add Strung function entry to the parser bytecode. - \throw nothrow - - A string function entry consists of the stack position of the return value, - followed by a cmSTRFUNC code, the function pointer and an index into the - string buffer maintained by the parser. - */ - void ParserByteCode::AddStrFun(generic_fun_type a_pFun, void* p, int a_iArgc, int a_iIdx) - { - m_iStackPos = m_iStackPos - a_iArgc + 1; - - SToken tok; - tok.Cmd = cmFUNC_STR; - tok.Fun.argc = a_iArgc; - tok.Fun.idx = a_iIdx; - tok.Fun.ptr = a_pFun; - tok.Fun.param = p; - tok.Fun.id = nextId++; - m_vRPN.push_back(tok); - - m_iMaxStackSize = std::max(m_iMaxStackSize, (size_t)m_iStackPos); - } - - //--------------------------------------------------------------------------- - /** \brief Add end marker to bytecode. - - \throw nothrow - */ - void ParserByteCode::Finalize() - { - SToken tok; - tok.Cmd = cmEND; - m_vRPN.push_back(tok); - rpn_type(m_vRPN).swap(m_vRPN); // shrink bytecode vector to fit - - // Determine the if-then-else jump offsets - ParserStack stIf, stElse; - int idx; - for (int i=0; i<(int)m_vRPN.size(); ++i) - { - switch(m_vRPN[i].Cmd) - { - case cmIF: - stIf.push(i); - break; - - case cmELSE: - stElse.push(i); - idx = stIf.pop(); - m_vRPN[idx].Oprt.offset = i - idx; - break; - - case cmENDIF: - idx = stElse.pop(); - m_vRPN[idx].Oprt.offset = i - idx; - break; - - default: - break; - } - } - } - - //--------------------------------------------------------------------------- - const SToken* ParserByteCode::GetBase() const - { - if (m_vRPN.size()==0) - throw ParserError(ecINTERNAL_ERROR); - else - return &m_vRPN[0]; - } - - //--------------------------------------------------------------------------- - std::size_t ParserByteCode::GetMaxStackSize() const - { - return m_iMaxStackSize+1; - } - - //--------------------------------------------------------------------------- - /** \brief Returns the number of entries in the bytecode. */ - std::size_t ParserByteCode::GetSize() const - { - return m_vRPN.size(); - } - - //--------------------------------------------------------------------------- - /** \brief Delete the bytecode. - - \throw nothrow - - The name of this function is a violation of my own coding guidelines - but this way it's more in line with the STL functions thus more - intuitive. - */ - void ParserByteCode::clear() - { - m_vRPN.clear(); - m_iStackPos = 0; - m_iMaxStackSize = 0; - } - - //--------------------------------------------------------------------------- - /** \brief Dump bytecode (for debugging only!). */ - void ParserByteCode::AsciiDump() - { - if (!m_vRPN.size()) - { - mu::console() << _T("No bytecode available\n"); - return; - } - - mu::console() << _T("Number of RPN tokens:") << (int)m_vRPN.size() << _T("\n"); - for (std::size_t i=0; i \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2004-2013 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -#ifndef MU_PARSER_BYTECODE_H -#define MU_PARSER_BYTECODE_H - -#include -#include -#include -#include - -#include "muParserDef.h" -#include "muParserError.h" -#include "muParserToken.h" - -/** \file - \brief Definition of the parser bytecode class. -*/ - - -namespace mu -{ - struct SToken - { - ECmdCode Cmd; - int StackPos; - - union - { - struct //SValData - { - value_type *ptr; - value_type data; - value_type data2; - } Val; - - struct //SFunData - { - // Note: generic_fun_type is merely a placeholder. The real type could be - // anything between gun_type1 and fun_type9. I can't use a void - // pointer due to constraints in the ANSI standard which allows - // data pointers and function pointers to differ in size. - generic_fun_type ptr; - int argc; - int idx; - int id; - void* param; - } Fun; - - struct //SOprtData - { - value_type *ptr; - int offset; - } Oprt; - }; - }; - - - /** \brief Bytecode implementation of the Math Parser. - - The bytecode contains the formula converted to revers polish notation stored in a continious - memory area. Associated with this data are operator codes, variable pointers, constant - values and function pointers. Those are necessary in order to calculate the result. - All those data items will be casted to the underlying datatype of the bytecode. - - \author (C) 2004-2013 Ingo Berg -*/ -class ParserByteCode -{ -private: - - /** \brief Token type for internal use only. */ - typedef ParserToken token_type; - - /** \brief Token vector for storing the RPN. */ - typedef std::vector rpn_type; - - /** \brief Position in the Calculation array. */ - unsigned m_iStackPos; - - /** \brief Maximum size needed for the stack. */ - std::size_t m_iMaxStackSize; - - /** \brief The actual rpn storage. */ - rpn_type m_vRPN; - - bool m_bEnableOptimizer; - - void ConstantFolding(ECmdCode a_Oprt); - - int nextId = 0; - -public: - - ParserByteCode(); - ParserByteCode(const ParserByteCode &a_ByteCode); - ParserByteCode& operator=(const ParserByteCode &a_ByteCode); - void Assign(const ParserByteCode &a_ByteCode); - - void AddVar(value_type *a_pVar); - void AddVal(value_type a_fVal); - void AddOp(ECmdCode a_Oprt); - void AddIfElse(ECmdCode a_Oprt); - void AddAssignOp(value_type *a_pVar); - void AddFun(generic_fun_type a_pFun, void* p, int a_iArgc); - void AddBulkFun(generic_fun_type a_pFun, void* p, int a_iArgc); - void AddStrFun(generic_fun_type a_pFun, void* p, int a_iArgc, int a_iIdx); - - void EnableOptimizer(bool bStat); - - void Finalize(); - void clear(); - std::size_t GetMaxStackSize() const; - std::size_t GetSize() const; - - const SToken* GetBase() const; - void AsciiDump(); -}; - -} // namespace mu - -#endif diff --git a/Modules/gin/3rdparty/muParser/muParserCallback.cpp b/Modules/gin/3rdparty/muParser/muParserCallback.cpp deleted file mode 100755 index 851dc59..0000000 --- a/Modules/gin/3rdparty/muParser/muParserCallback.cpp +++ /dev/null @@ -1,497 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2004-2011 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "muParserCallback.h" - -/** \file - \brief Implementation of the parser callback class. -*/ - - -namespace mu -{ - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type0 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(0) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type1 a_pFun, void* p, bool a_bAllowOpti, int a_iPrec, ECmdCode a_iCode) - :m_pFun((void*)a_pFun) - ,m_iArgc(1) - ,m_iPri(a_iPrec) - ,m_eOprtAsct(oaNONE) - ,m_iCode(a_iCode) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - - //--------------------------------------------------------------------------- - /** \brief Constructor for constructing function callbacks taking two arguments. - \throw nothrow - */ - ParserCallback::ParserCallback(fun_type2 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(2) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - /** \brief Constructor for constructing binary operator callbacks. - \param a_pFun Pointer to a static function taking two arguments - \param a_bAllowOpti A flag indicating this function can be optimized - \param a_iPrec The operator precedence - \param a_eOprtAsct The operators associativity - \throw nothrow - */ - ParserCallback::ParserCallback(fun_type2 a_pFun, - void* p, bool a_bAllowOpti, - int a_iPrec, - EOprtAssociativity a_eOprtAsct) - :m_pFun((void*)a_pFun) - ,m_iArgc(2) - ,m_iPri(a_iPrec) - ,m_eOprtAsct(a_eOprtAsct) - ,m_iCode(cmOPRT_BIN) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type3 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(3) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type4 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(4) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type5 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(5) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type6 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(6) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type7 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(7) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type8 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(8) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type9 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(9) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(fun_type10 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(10) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type0 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(0) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type1 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(1) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - - //--------------------------------------------------------------------------- - /** \brief Constructor for constructing function callbacks taking two arguments. - \throw nothrow - */ - ParserCallback::ParserCallback(bulkfun_type2 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(2) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type3 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(3) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type4 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(4) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type5 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(5) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type6 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(6) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type7 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(7) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type8 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(8) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type9 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(9) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(bulkfun_type10 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(10) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_BULK) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(multfun_type a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(-1) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC) - ,m_iType(tpDBL) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(strfun_type1 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(0) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_STR) - ,m_iType(tpSTR) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(strfun_type2 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(1) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_STR) - ,m_iType(tpSTR) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - - //--------------------------------------------------------------------------- - ParserCallback::ParserCallback(strfun_type3 a_pFun, void* p, bool a_bAllowOpti) - :m_pFun((void*)a_pFun) - ,m_iArgc(2) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmFUNC_STR) - ,m_iType(tpSTR) - ,m_bAllowOpti(a_bAllowOpti) - ,m_param(p) - {} - - - //--------------------------------------------------------------------------- - /** \brief Default constructor. - \throw nothrow - */ - ParserCallback::ParserCallback() - :m_pFun(nullptr) - ,m_iArgc(0) - ,m_iPri(-1) - ,m_eOprtAsct(oaNONE) - ,m_iCode(cmUNKNOWN) - ,m_iType(tpVOID) - ,m_bAllowOpti(0) - ,m_param(nullptr) - {} - - - //--------------------------------------------------------------------------- - /** \brief Copy constructor. - \throw nothrow - */ - ParserCallback::ParserCallback(const ParserCallback &ref) - { - m_pFun = ref.m_pFun; - m_iArgc = ref.m_iArgc; - m_bAllowOpti = ref.m_bAllowOpti; - m_iCode = ref.m_iCode; - m_iType = ref.m_iType; - m_iPri = ref.m_iPri; - m_eOprtAsct = ref.m_eOprtAsct; - m_param = ref.m_param; - } - - //--------------------------------------------------------------------------- - /** \brief Clone this instance and return a pointer to the new instance. */ - ParserCallback* ParserCallback::Clone() const - { - return new ParserCallback(*this); - } - - //--------------------------------------------------------------------------- - /** \brief Return tru if the function is conservative. - - Conservative functions return always the same result for the same argument. - \throw nothrow - */ - bool ParserCallback::IsOptimizable() const - { - return m_bAllowOpti; - } - - //--------------------------------------------------------------------------- - /** \brief Get the callback address for the parser function. - - The type of the address is void. It needs to be recasted according to the - argument number to the right type. - - \throw nothrow - \return #pFun - */ - void* ParserCallback::GetAddr() const - { - return m_pFun; - } - - void* ParserCallback::GetParam() const - { - return m_param; - } - - //--------------------------------------------------------------------------- - /** \brief Return the callback code. */ - ECmdCode ParserCallback::GetCode() const - { - return m_iCode; - } - - //--------------------------------------------------------------------------- - ETypeCode ParserCallback::GetType() const - { - return m_iType; - } - - - //--------------------------------------------------------------------------- - /** \brief Return the operator precedence. - \throw nothrown - - Only valid if the callback token is an operator token (binary or infix). - */ - int ParserCallback::GetPri() const - { - return m_iPri; - } - - //--------------------------------------------------------------------------- - /** \brief Return the operators associativity. - \throw nothrown - - Only valid if the callback token is a binary operator token. - */ - EOprtAssociativity ParserCallback::GetAssociativity() const - { - return m_eOprtAsct; - } - - //--------------------------------------------------------------------------- - /** \brief Returns the number of function Arguments. */ - int ParserCallback::GetArgc() const - { - return m_iArgc; - } -} // namespace mu diff --git a/Modules/gin/3rdparty/muParser/muParserCallback.h b/Modules/gin/3rdparty/muParser/muParserCallback.h deleted file mode 100755 index 09788ac..0000000 --- a/Modules/gin/3rdparty/muParser/muParserCallback.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2004-2011 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef MU_PARSER_CALLBACK_H -#define MU_PARSER_CALLBACK_H - -#include "muParserDef.h" - -/** \file - \brief Definition of the parser callback class. -*/ - -namespace mu -{ - -/** \brief Encapsulation of prototypes for a numerical parser function. - - Encapsulates the prototyp for numerical parser functions. The class - stores the number of arguments for parser functions as well - as additional flags indication the function is non optimizeable. - The pointer to the callback function pointer is stored as void* - and needs to be casted according to the argument count. - Negative argument counts indicate a parser function with a variable number - of arguments. - - \author (C) 2004-2011 Ingo Berg -*/ -class ParserCallback -{ -public: - ParserCallback(fun_type0 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(fun_type1 a_pFun, void* p, bool a_bAllowOpti, int a_iPrec = -1, ECmdCode a_iCode=cmFUNC); - ParserCallback(fun_type2 a_pFun, void* p, bool a_bAllowOpti, int a_iPrec, EOprtAssociativity a_eAssociativity); - ParserCallback(fun_type2 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(fun_type3 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(fun_type4 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(fun_type5 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(fun_type6 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(fun_type7 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(fun_type8 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(fun_type9 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(fun_type10 a_pFun, void* p, bool a_bAllowOpti); - - ParserCallback(bulkfun_type0 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(bulkfun_type1 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(bulkfun_type2 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(bulkfun_type3 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(bulkfun_type4 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(bulkfun_type5 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(bulkfun_type6 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(bulkfun_type7 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(bulkfun_type8 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(bulkfun_type9 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(bulkfun_type10 a_pFun, void* p, bool a_bAllowOpti); - - ParserCallback(multfun_type a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(strfun_type1 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(strfun_type2 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(strfun_type3 a_pFun, void* p, bool a_bAllowOpti); - ParserCallback(); - ParserCallback(const ParserCallback &a_Fun); - - ParserCallback* Clone() const; - - bool IsOptimizable() const; - void* GetAddr() const; - void* GetParam() const; - ECmdCode GetCode() const; - ETypeCode GetType() const; - int GetPri() const; - EOprtAssociativity GetAssociativity() const; - int GetArgc() const; - -private: - void *m_pFun; ///< Pointer to the callback function, casted to void - - /** \brief Number of numeric function arguments - - This number is negative for functions with variable number of arguments. in this cases - they represent the actual number of arguments found. - */ - int m_iArgc; - int m_iPri; ///< Valid only for binary and infix operators; Operator precedence. - EOprtAssociativity m_eOprtAsct; ///< Operator associativity; Valid only for binary operators - ECmdCode m_iCode; - ETypeCode m_iType; - bool m_bAllowOpti; ///< Flag indication optimizeability - void* m_param = nullptr; -}; - -//------------------------------------------------------------------------------ -/** \brief Container for Callback objects. */ -typedef std::map funmap_type; - -} // namespace mu - -#endif diff --git a/Modules/gin/3rdparty/muParser/muParserDef.h b/Modules/gin/3rdparty/muParser/muParserDef.h deleted file mode 100755 index d1c08e9..0000000 --- a/Modules/gin/3rdparty/muParser/muParserDef.h +++ /dev/null @@ -1,372 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2014 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -#ifndef MUP_DEF_H -#define MUP_DEF_H - -#include -#include -#include -#include - -#include "muParserFixes.h" - -/** \file - \brief This file contains standard definitions used by the parser. -*/ - -#define MUP_VERSION _T("2.2.5") -#define MUP_VERSION_DATE _T("20150427; GC") - -#define MUP_CHARS _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") - -/** \brief If this macro is defined mathematical exceptions (div by zero) will be thrown as exceptions. */ -//#define MUP_MATH_EXCEPTIONS - -/** \brief Define the base datatype for values. - - This datatype must be a built in value type. You can not use custom classes. - It should be working with all types except "int"! -*/ -#define MUP_BASETYPE double - -/** \brief Activate this option in order to compile with OpenMP support. - - OpenMP is used only in the bulk mode it may increase the performance a bit. -*/ -//#define MUP_USE_OPENMP - -#if defined(_UNICODE) - /** \brief Definition of the basic parser string type. */ - #define MUP_STRING_TYPE std::wstring - - #if !defined(_T) - #define _T(x) L##x - #endif // not defined _T -#else - #ifndef _T - #define _T(x) x - #endif - - /** \brief Definition of the basic parser string type. */ - #define MUP_STRING_TYPE std::string -#endif - -#if defined(_DEBUG) - /** \brief Debug macro to force an abortion of the programm with a certain message. - */ - #define MUP_FAIL(MSG) \ - { \ - bool MSG=false; \ - assert(MSG); \ - } - - /** \brief An assertion that does not kill the program. - - This macro is neutralised in UNICODE builds. It's - too difficult to translate. - */ - #define MUP_ASSERT(COND) \ - if (!(COND)) \ - { \ - stringstream_type ss; \ - ss << _T("Assertion \"") _T(#COND) _T("\" failed: ") \ - << __FILE__ << _T(" line ") \ - << __LINE__ << _T("."); \ - throw ParserError( ss.str() ); \ - } -#else - #define MUP_FAIL(MSG) - #define MUP_ASSERT(COND) -#endif - - -namespace mu -{ -#if defined(_UNICODE) - - //------------------------------------------------------------------------------ - /** \brief Encapsulate wcout. */ - inline std::wostream& console() - { - return std::wcout; - } - - /** \brief Encapsulate cin. */ - inline std::wistream& console_in() - { - return std::wcin; - } - -#else - - /** \brief Encapsulate cout. - - Used for supporting UNICODE more easily. - */ - inline std::ostream& console() - { - return std::cout; - } - - /** \brief Encapsulate cin. - - Used for supporting UNICODE more easily. - */ - inline std::istream& console_in() - { - return std::cin; - } - -#endif - - //------------------------------------------------------------------------------ - /** \brief Bytecode values. - - \attention The order of the operator entries must match the order in ParserBase::c_DefaultOprt! - */ - enum ECmdCode - { - // The following are codes for built in binary operators - // apart from built in operators the user has the opportunity to - // add user defined operators. - cmLE = 0, ///< Operator item: less or equal - cmGE = 1, ///< Operator item: greater or equal - cmNEQ = 2, ///< Operator item: not equal - cmEQ = 3, ///< Operator item: equals - cmLT = 4, ///< Operator item: less than - cmGT = 5, ///< Operator item: greater than - cmADD = 6, ///< Operator item: add - cmSUB = 7, ///< Operator item: subtract - cmMUL = 8, ///< Operator item: multiply - cmDIV = 9, ///< Operator item: division - cmPOW = 10, ///< Operator item: y to the power of ... - cmLAND = 11, - cmLOR = 12, - cmASSIGN = 13, ///< Operator item: Assignment operator - cmBO = 14, ///< Operator item: opening bracket - cmBC = 15, ///< Operator item: closing bracket - cmIF = 16, ///< For use in the ternary if-then-else operator - cmELSE = 17, ///< For use in the ternary if-then-else operator - cmENDIF = 18, ///< For use in the ternary if-then-else operator - cmARG_SEP = 19, ///< function argument separator - cmVAR = 20, ///< variable item - cmVAL = 21, ///< value item - - // For optimization purposes - cmVARPOW2, - cmVARPOW3, - cmVARPOW4, - cmVARMUL, - cmPOW2, - - // operators and functions - cmFUNC, ///< Code for a generic function item - cmFUNC_STR, ///< Code for a function with a string parameter - cmFUNC_BULK, ///< Special callbacks for Bulk mode with an additional parameter for the bulk index - cmSTRING, ///< Code for a string token - cmOPRT_BIN, ///< user defined binary operator - cmOPRT_POSTFIX, ///< code for postfix operators - cmOPRT_INFIX, ///< code for infix operators - cmEND, ///< end of formula - cmUNKNOWN ///< uninitialized item - }; - - //------------------------------------------------------------------------------ - /** \brief Types internally used by the parser. - */ - enum ETypeCode - { - tpSTR = 0, ///< String type (Function arguments and constants only, no string variables) - tpDBL = 1, ///< Floating point variables - tpVOID = 2 ///< Undefined type. - }; - - //------------------------------------------------------------------------------ - enum EParserVersionInfo - { - pviBRIEF, - pviFULL - }; - - //------------------------------------------------------------------------------ - /** \brief Parser operator precedence values. */ - enum EOprtAssociativity - { - oaLEFT = 0, - oaRIGHT = 1, - oaNONE = 2 - }; - - //------------------------------------------------------------------------------ - /** \brief Parser operator precedence values. */ - enum EOprtPrecedence - { - // binary operators - prLOR = 1, - prLAND = 2, - prLOGIC = 3, ///< logic operators - prCMP = 4, ///< comparsion operators - prADD_SUB = 5, ///< addition - prMUL_DIV = 6, ///< multiplication/division - prPOW = 7, ///< power operator priority (highest) - - // infix operators - prINFIX = 6, ///< Signs have a higher priority than ADD_SUB, but lower than power operator - prPOSTFIX = 6 ///< Postfix operator priority (currently unused) - }; - - //------------------------------------------------------------------------------ - // basic types - - /** \brief The numeric datatype used by the parser. - - Normally this is a floating point type either single or double precision. - */ - typedef MUP_BASETYPE value_type; - - /** \brief The stringtype used by the parser. - - Depends on whether UNICODE is used or not. - */ - typedef MUP_STRING_TYPE string_type; - - /** \brief The character type used by the parser. - - Depends on whether UNICODE is used or not. - */ - typedef string_type::value_type char_type; - - /** \brief Typedef for easily using stringstream that respect the parser stringtype. */ - typedef std::basic_stringstream, - std::allocator > stringstream_type; - - // Data container types - - /** \brief Type used for storing variables. */ - typedef std::map varmap_type; - - /** \brief Type used for storing constants. */ - typedef std::map valmap_type; - - /** \brief Type for assigning a string name to an index in the internal string table. */ - typedef std::map strmap_type; - - // Parser callbacks - struct SParam - { - void* param = nullptr; - int id = 0; - }; - - /** \brief Callback type used for functions without arguments. */ - typedef value_type (*generic_fun_type)(SParam); - - /** \brief Callback type used for functions without arguments. */ - typedef value_type (*fun_type0)(SParam); - - /** \brief Callback type used for functions with a single arguments. */ - typedef value_type (*fun_type1)(SParam, value_type); - - /** \brief Callback type used for functions with two arguments. */ - typedef value_type (*fun_type2)(SParam, value_type, value_type); - - /** \brief Callback type used for functions with three arguments. */ - typedef value_type (*fun_type3)(SParam, value_type, value_type, value_type); - - /** \brief Callback type used for functions with four arguments. */ - typedef value_type (*fun_type4)(SParam, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*fun_type5)(SParam, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with six arguments. */ - typedef value_type (*fun_type6)(SParam, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with seven arguments. */ - typedef value_type (*fun_type7)(SParam, value_type, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with eight arguments. */ - typedef value_type (*fun_type8)(SParam, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with nine arguments. */ - typedef value_type (*fun_type9)(SParam, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with ten arguments. */ - typedef value_type (*fun_type10)(SParam, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions without arguments. */ - typedef value_type (*bulkfun_type0)(SParam, int, int); - - /** \brief Callback type used for functions with a single arguments. */ - typedef value_type (*bulkfun_type1)(SParam, int, int, value_type); - - /** \brief Callback type used for functions with two arguments. */ - typedef value_type (*bulkfun_type2)(SParam, int, int, value_type, value_type); - - /** \brief Callback type used for functions with three arguments. */ - typedef value_type (*bulkfun_type3)(SParam, int, int, value_type, value_type, value_type); - - /** \brief Callback type used for functions with four arguments. */ - typedef value_type (*bulkfun_type4)(SParam, int, int, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with five arguments. */ - typedef value_type (*bulkfun_type5)(SParam, int, int, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with six arguments. */ - typedef value_type (*bulkfun_type6)(SParam, int, int, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with seven arguments. */ - typedef value_type (*bulkfun_type7)(SParam, int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with eight arguments. */ - typedef value_type (*bulkfun_type8)(SParam, int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with nine arguments. */ - typedef value_type (*bulkfun_type9)(SParam, int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with ten arguments. */ - typedef value_type (*bulkfun_type10)(SParam, int, int, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type, value_type); - - /** \brief Callback type used for functions with a variable argument list. */ - typedef value_type (*multfun_type)(SParam, const value_type*, int); - - /** \brief Callback type used for functions taking a string as an argument. */ - typedef value_type (*strfun_type1)(SParam, const char_type*); - - /** \brief Callback type used for functions taking a string and a value as arguments. */ - typedef value_type (*strfun_type2)(SParam, const char_type*, value_type); - - /** \brief Callback type used for functions taking a string and two values as arguments. */ - typedef value_type (*strfun_type3)(SParam, const char_type*, value_type, value_type); - - /** \brief Callback used for functions that identify values in a string. */ - typedef int (*identfun_type)(SParam, const char_type *sExpr, int *nPos, value_type *fVal); - - /** \brief Callback used for variable creation factory functions. */ - typedef value_type* (*facfun_type)(SParam, const char_type*, void*); -} // end of namespace - -#endif diff --git a/Modules/gin/3rdparty/muParser/muParserError.cpp b/Modules/gin/3rdparty/muParser/muParserError.cpp deleted file mode 100755 index effcefe..0000000 --- a/Modules/gin/3rdparty/muParser/muParserError.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2011 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -#include "muParserError.h" - -#if __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#endif - -namespace mu -{ - const ParserErrorMsg ParserErrorMsg::m_Instance; - - //------------------------------------------------------------------------------ - const ParserErrorMsg& ParserErrorMsg::Instance() - { - return m_Instance; - } - - //------------------------------------------------------------------------------ - string_type ParserErrorMsg::operator[](unsigned a_iIdx) const - { - return (a_iIdx \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2004-2011 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef MU_PARSER_ERROR_H -#define MU_PARSER_ERROR_H - -#include -#include -#include -#include -#include -#include - -#include "muParserDef.h" - -/** \file - \brief This file defines the error class used by the parser. -*/ - -namespace mu -{ - -/** \brief Error codes. */ -enum EErrorCodes -{ - // Formula syntax errors - ecUNEXPECTED_OPERATOR = 0, ///< Unexpected binary operator found - ecUNASSIGNABLE_TOKEN = 1, ///< Token can't be identified. - ecUNEXPECTED_EOF = 2, ///< Unexpected end of formula. (Example: "2+sin(") - ecUNEXPECTED_ARG_SEP = 3, ///< An unexpected comma has been found. (Example: "1,23") - ecUNEXPECTED_ARG = 4, ///< An unexpected argument has been found - ecUNEXPECTED_VAL = 5, ///< An unexpected value token has been found - ecUNEXPECTED_VAR = 6, ///< An unexpected variable token has been found - ecUNEXPECTED_PARENS = 7, ///< Unexpected Parenthesis, opening or closing - ecUNEXPECTED_STR = 8, ///< A string has been found at an inapropriate position - ecSTRING_EXPECTED = 9, ///< A string function has been called with a different type of argument - ecVAL_EXPECTED = 10, ///< A numerical function has been called with a non value type of argument - ecMISSING_PARENS = 11, ///< Missing parens. (Example: "3*sin(3") - ecUNEXPECTED_FUN = 12, ///< Unexpected function found. (Example: "sin(8)cos(9)") - ecUNTERMINATED_STRING = 13, ///< unterminated string constant. (Example: "3*valueof("hello)") - ecTOO_MANY_PARAMS = 14, ///< Too many function parameters - ecTOO_FEW_PARAMS = 15, ///< Too few function parameters. (Example: "ite(1<2,2)") - ecOPRT_TYPE_CONFLICT = 16, ///< binary operators may only be applied to value items of the same type - ecSTR_RESULT = 17, ///< result is a string - - // Invalid Parser input Parameters - ecINVALID_NAME = 18, ///< Invalid function, variable or constant name. - ecINVALID_BINOP_IDENT = 19, ///< Invalid binary operator identifier - ecINVALID_INFIX_IDENT = 20, ///< Invalid function, variable or constant name. - ecINVALID_POSTFIX_IDENT = 21, ///< Invalid function, variable or constant name. - - ecBUILTIN_OVERLOAD = 22, ///< Trying to overload builtin operator - ecINVALID_FUN_PTR = 23, ///< Invalid callback function pointer - ecINVALID_VAR_PTR = 24, ///< Invalid variable pointer - ecEMPTY_EXPRESSION = 25, ///< The Expression is empty - ecNAME_CONFLICT = 26, ///< Name conflict - ecOPT_PRI = 27, ///< Invalid operator priority - // - ecDOMAIN_ERROR = 28, ///< catch division by zero, sqrt(-1), log(0) (currently unused) - ecDIV_BY_ZERO = 29, ///< Division by zero (currently unused) - ecGENERIC = 30, ///< Generic error - ecLOCALE = 31, ///< Conflict with current locale - - ecUNEXPECTED_CONDITIONAL = 32, - ecMISSING_ELSE_CLAUSE = 33, - ecMISPLACED_COLON = 34, - - ecUNREASONABLE_NUMBER_OF_COMPUTATIONS = 35, - - // internal errors - ecINTERNAL_ERROR = 36, ///< Internal error of any kind. - - // The last two are special entries - ecCOUNT, ///< This is no error code, It just stores just the total number of error codes - ecUNDEFINED = -1 ///< Undefined message, placeholder to detect unassigned error messages -}; - -//--------------------------------------------------------------------------- -/** \brief A class that handles the error messages. -*/ -class ParserErrorMsg -{ -public: - typedef ParserErrorMsg self_type; - - ParserErrorMsg& operator=(const ParserErrorMsg &); - ParserErrorMsg(const ParserErrorMsg&); - ParserErrorMsg(); - - ~ParserErrorMsg(); - - static const ParserErrorMsg& Instance(); - string_type operator[](unsigned a_iIdx) const; - -private: - std::vector m_vErrMsg; ///< A vector with the predefined error messages - static const self_type m_Instance; ///< The instance pointer -}; - -//--------------------------------------------------------------------------- -/** \brief Error class of the parser. - \author Ingo Berg - - Part of the math parser package. -*/ -class ParserError -{ -private: - - /** \brief Replace all ocuurences of a substring with another string. */ - void ReplaceSubString( string_type &strSource, - const string_type &strFind, - const string_type &strReplaceWith); - void Reset(); - -public: - - ParserError(); - explicit ParserError(EErrorCodes a_iErrc); - explicit ParserError(const string_type &sMsg); - ParserError( EErrorCodes a_iErrc, - const string_type &sTok, - const string_type &sFormula = string_type(), - int a_iPos = -1); - ParserError( EErrorCodes a_iErrc, - int a_iPos, - const string_type &sTok); - ParserError( const char_type *a_szMsg, - int a_iPos = -1, - const string_type &sTok = string_type()); - ParserError(const ParserError &a_Obj); - ParserError& operator=(const ParserError &a_Obj); - ~ParserError(); - - void SetFormula(const string_type &a_strFormula); - const string_type& GetExpr() const; - const string_type& GetMsg() const; - int GetPos() const; - const string_type& GetToken() const; - EErrorCodes GetCode() const; - -private: - string_type m_strMsg; ///< The message string - string_type m_strFormula; ///< Formula string - string_type m_strTok; ///< Token related with the error - int m_iPos; ///< Formula position related to the error - EErrorCodes m_iErrc; ///< Error code - const ParserErrorMsg &m_ErrMsg; -}; - -} // namespace mu - -#endif diff --git a/Modules/gin/3rdparty/muParser/muParserFixes.h b/Modules/gin/3rdparty/muParser/muParserFixes.h deleted file mode 100755 index d67fca7..0000000 --- a/Modules/gin/3rdparty/muParser/muParserFixes.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2013 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef MU_PARSER_FIXES_H -#define MU_PARSER_FIXES_H - -/** \file - \brief This file contains compatibility fixes for some platforms. -*/ - -// -// Compatibility fixes -// - -//--------------------------------------------------------------------------- -// -// Intel Compiler -// -//--------------------------------------------------------------------------- - -#ifdef __INTEL_COMPILER - -// remark #981: operands are evaluated in unspecified order -// disabled -> completely pointless if the functions do not have side effects -// -#pragma warning(disable:981) - -// remark #383: value copied to temporary, reference to temporary used -#pragma warning(disable:383) - -// remark #1572: floating-point equality and inequality comparisons are unreliable -// disabled -> everyone knows it, the parser passes this problem -// deliberately to the user -#pragma warning(disable:1572) - -#endif - -#endif // include guard diff --git a/Modules/gin/3rdparty/muParser/muParserStack.h b/Modules/gin/3rdparty/muParser/muParserStack.h deleted file mode 100755 index 70f25a5..0000000 --- a/Modules/gin/3rdparty/muParser/muParserStack.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2004-2011 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef MU_PARSER_STACK_H -#define MU_PARSER_STACK_H - -#include -#include -#include -#include - -#include "muParserError.h" -#include "muParserToken.h" - -/** \file - \brief This file defines the stack used by muparser. -*/ - -namespace mu -{ - - /** \brief Parser stack implementation. - - Stack implementation based on a std::stack. The behaviour of pop() had been - slightly changed in order to get an error code if the stack is empty. - The stack is used within the Parser both as a value stack and as an operator stack. - - \author (C) 2004-2011 Ingo Berg - */ - template - class ParserStack - { - private: - - /** \brief Type of the underlying stack implementation. */ - typedef std::stack > impl_type; - - impl_type m_Stack; ///< This is the actual stack. - - public: - - //--------------------------------------------------------------------------- - ParserStack() - :m_Stack() - {} - - //--------------------------------------------------------------------------- - virtual ~ParserStack() - {} - - //--------------------------------------------------------------------------- - /** \brief Pop a value from the stack. - - Unlike the standard implementation this function will return the value that - is going to be taken from the stack. - - \throw ParserException in case the stack is empty. - \sa pop(int &a_iErrc) - */ - TValueType pop() - { - if (empty()) - throw ParserError( _T("stack is empty.") ); - - TValueType el = top(); - m_Stack.pop(); - return el; - } - - /** \brief Push an object into the stack. - - \param a_Val object to push into the stack. - \throw nothrow - */ - void push(const TValueType& a_Val) - { - m_Stack.push(a_Val); - } - - /** \brief Return the number of stored elements. */ - unsigned size() const - { - return (unsigned)m_Stack.size(); - } - - /** \brief Returns true if stack is empty false otherwise. */ - bool empty() const - { - return m_Stack.empty(); - } - - /** \brief Return reference to the top object in the stack. - - The top object is the one pushed most recently. - */ - TValueType& top() - { - return m_Stack.top(); - } - }; -} // namespace MathUtils - -#endif diff --git a/Modules/gin/3rdparty/muParser/muParserTemplateMagic.h b/Modules/gin/3rdparty/muParser/muParserTemplateMagic.h deleted file mode 100755 index d212fda..0000000 --- a/Modules/gin/3rdparty/muParser/muParserTemplateMagic.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef MU_PARSER_TEMPLATE_MAGIC_H -#define MU_PARSER_TEMPLATE_MAGIC_H - -#include -#include "muParserError.h" - - -namespace mu -{ - //----------------------------------------------------------------------------------------------- - // - // Compile time type detection - // - //----------------------------------------------------------------------------------------------- - - /** \brief A class singling out integer types at compile time using - template meta programming. - */ - template - struct TypeInfo - { - static bool IsInteger() { return false; } - }; - - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; - - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; - - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; - - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; - - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; - - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; - - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; - - template<> - struct TypeInfo - { - static bool IsInteger() { return true; } - }; - - - //----------------------------------------------------------------------------------------------- - // - // Standard math functions with dummy overload for integer types - // - //----------------------------------------------------------------------------------------------- - - /** \brief A template class for providing wrappers for essential math functions. - - This template is spezialized for several types in order to provide a unified interface - for parser internal math function calls regardless of the data type. - */ - template - struct MathImpl - { - static T Sin(T v) { return sin(v); } - static T Cos(T v) { return cos(v); } - static T Tan(T v) { return tan(v); } - static T ASin(T v) { return asin(v); } - static T ACos(T v) { return acos(v); } - static T ATan(T v) { return atan(v); } - static T ATan2(T v1, T v2) { return atan2(v1, v2); } - static T Sinh(T v) { return sinh(v); } - static T Cosh(T v) { return cosh(v); } - static T Tanh(T v) { return tanh(v); } - static T ASinh(T v) { return log(v + sqrt(v * v + 1)); } - static T ACosh(T v) { return log(v + sqrt(v * v - 1)); } - static T ATanh(T v) { return ((T)0.5 * log((1 + v) / (1 - v))); } - static T Log(T v) { return log(v); } - static T Log2(T v) { return log(v)/log((T)2); } // Logarithm base 2 - static T Log10(T v) { return log10(v); } // Logarithm base 10 - static T Exp(T v) { return exp(v); } - static T Abs(T v) { return (v>=0) ? v : -v; } - static T Sqrt(T v) { return sqrt(v); } - static T Rint(T v) { return floor(v + (T)0.5); } - static T Sign(T v) { return (T)((v<0) ? -1 : (v>0) ? 1 : 0); } - static T Pow(T v1, T v2) { return std::pow(v1, v2); } - }; -} - -#endif diff --git a/Modules/gin/3rdparty/muParser/muParserToken.h b/Modules/gin/3rdparty/muParser/muParserToken.h deleted file mode 100755 index 09dc486..0000000 --- a/Modules/gin/3rdparty/muParser/muParserToken.h +++ /dev/null @@ -1,406 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2004-2013 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef MU_PARSER_TOKEN_H -#define MU_PARSER_TOKEN_H - -#include -#include -#include -#include -#include - -#include "muParserError.h" -#include "muParserCallback.h" - -/** \file - \brief This file contains the parser token definition. -*/ - -namespace mu -{ - /** \brief Encapsulation of the data for a single formula token. - - Formula token implementation. Part of the Math Parser Package. - Formula tokens can be either one of the following: -
    -
  • value
  • -
  • variable
  • -
  • function with numerical arguments
  • -
  • functions with a string as argument
  • -
  • prefix operators
  • -
  • infix operators
  • -
  • binary operator
  • -
- - \author (C) 2004-2013 Ingo Berg - */ - template - class ParserToken - { - private: - - ECmdCode m_iCode; ///< Type of the token; The token type is a constant of type #ECmdCode. - ETypeCode m_iType; - void *m_pTok; ///< Stores Token pointer; not applicable for all tokens - int m_iIdx; ///< An otional index to an external buffer storing the token data - TString m_strTok; ///< Token string - TString m_strVal; ///< Value for string variables - value_type m_fVal; ///< the value - std::unique_ptr m_pCallback; - - public: - - //--------------------------------------------------------------------------- - /** \brief Constructor (default). - - Sets token to an neutral state of type cmUNKNOWN. - \throw nothrow - \sa ECmdCode - */ - ParserToken() - :m_iCode(cmUNKNOWN) - ,m_iType(tpVOID) - ,m_pTok(nullptr) - ,m_iIdx(-1) - ,m_strTok() - ,m_strVal() - ,m_fVal(0) - ,m_pCallback() - {} - - //------------------------------------------------------------------------------ - /** \brief Create token from another one. - - Implemented by calling Assign(...) - \throw nothrow - \post m_iType==cmUNKNOWN - \sa #Assign - */ - ParserToken(const ParserToken &a_Tok) - { - Assign(a_Tok); - } - - //------------------------------------------------------------------------------ - /** \brief Assignment operator. - - Copy token state from another token and return this. - Implemented by calling Assign(...). - \throw nothrow - */ - ParserToken& operator=(const ParserToken &a_Tok) - { - Assign(a_Tok); - return *this; - } - - //------------------------------------------------------------------------------ - /** \brief Copy token information from argument. - - \throw nothrow - */ - void Assign(const ParserToken &a_Tok) - { - m_iCode = a_Tok.m_iCode; - m_pTok = a_Tok.m_pTok; - m_strTok = a_Tok.m_strTok; - m_iIdx = a_Tok.m_iIdx; - m_strVal = a_Tok.m_strVal; - m_iType = a_Tok.m_iType; - m_fVal = a_Tok.m_fVal; - // create new callback object if a_Tok has one - m_pCallback.reset(a_Tok.m_pCallback.get() ? a_Tok.m_pCallback->Clone() : nullptr); - } - - //------------------------------------------------------------------------------ - /** \brief Assign a token type. - - Token may not be of type value, variable or function. Those have separate set functions. - - \pre [assert] a_iType!=cmVAR - \pre [assert] a_iType!=cmVAL - \pre [assert] a_iType!=cmFUNC - \post m_fVal = 0 - \post m_pTok = 0 - */ - ParserToken& Set(ECmdCode a_iType, const TString &a_strTok=TString()) - { - // The following types can't be set this way, they have special Set functions - assert(a_iType!=cmVAR); - assert(a_iType!=cmVAL); - assert(a_iType!=cmFUNC); - - m_iCode = a_iType; - m_iType = tpVOID; - m_pTok = nullptr; - m_strTok = a_strTok; - m_iIdx = -1; - - return *this; - } - - //------------------------------------------------------------------------------ - /** \brief Set Callback type. */ - ParserToken& Set(const ParserCallback &a_pCallback, const TString &a_sTok) - { - assert(a_pCallback.GetAddr()); - - m_iCode = a_pCallback.GetCode(); - m_iType = tpVOID; - m_strTok = a_sTok; - m_pCallback.reset(new ParserCallback(a_pCallback)); - - m_pTok = nullptr; - m_iIdx = -1; - - return *this; - } - - //------------------------------------------------------------------------------ - /** \brief Make this token a value token. - - Member variables not necessary for value tokens will be invalidated. - \throw nothrow - */ - ParserToken& SetVal(TBase a_fVal, const TString &a_strTok=TString()) - { - m_iCode = cmVAL; - m_iType = tpDBL; - m_fVal = a_fVal; - m_strTok = a_strTok; - m_iIdx = -1; - - m_pTok = nullptr; - m_pCallback.reset(nullptr); - - return *this; - } - - //------------------------------------------------------------------------------ - /** \brief make this token a variable token. - - Member variables not necessary for variable tokens will be invalidated. - \throw nothrow - */ - ParserToken& SetVar(TBase *a_pVar, const TString &a_strTok) - { - m_iCode = cmVAR; - m_iType = tpDBL; - m_strTok = a_strTok; - m_iIdx = -1; - m_pTok = (void*)a_pVar; - m_pCallback.reset(nullptr); - return *this; - } - - //------------------------------------------------------------------------------ - /** \brief Make this token a variable token. - - Member variables not necessary for variable tokens will be invalidated. - \throw nothrow - */ - ParserToken& SetString(const TString &a_strTok, std::size_t a_iSize) - { - m_iCode = cmSTRING; - m_iType = tpSTR; - m_strTok = a_strTok; - m_iIdx = static_cast(a_iSize); - - m_pTok = nullptr; - m_pCallback.reset(nullptr); - return *this; - } - - //------------------------------------------------------------------------------ - /** \brief Set an index associated with the token related data. - - In cmSTRFUNC - This is the index to a string table in the main parser. - \param a_iIdx The index the string function result will take in the bytecode parser. - \throw exception_type if #a_iIdx<0 or #m_iType!=cmSTRING - */ - void SetIdx(int a_iIdx) - { - if (m_iCode!=cmSTRING || a_iIdx<0) - throw ParserError(ecINTERNAL_ERROR); - - m_iIdx = a_iIdx; - } - - //------------------------------------------------------------------------------ - /** \brief Return Index associated with the token related data. - - In cmSTRFUNC - This is the index to a string table in the main parser. - - \throw exception_type if #m_iIdx<0 or #m_iType!=cmSTRING - \return The index the result will take in the Bytecode calculatin array (#m_iIdx). - */ - int GetIdx() const - { - if (m_iIdx<0 || m_iCode!=cmSTRING ) - throw ParserError(ecINTERNAL_ERROR); - - return m_iIdx; - } - - //------------------------------------------------------------------------------ - /** \brief Return the token type. - - \return #m_iType - \throw nothrow - */ - ECmdCode GetCode() const - { - if (m_pCallback.get()) - { - return m_pCallback->GetCode(); - } - else - { - return m_iCode; - } - } - - //------------------------------------------------------------------------------ - ETypeCode GetType() const - { - if (m_pCallback.get()) - { - return m_pCallback->GetType(); - } - else - { - return m_iType; - } - } - - //------------------------------------------------------------------------------ - int GetPri() const - { - if ( !m_pCallback.get()) - throw ParserError(ecINTERNAL_ERROR); - - if ( m_pCallback->GetCode()!=cmOPRT_BIN && m_pCallback->GetCode()!=cmOPRT_INFIX) - throw ParserError(ecINTERNAL_ERROR); - - return m_pCallback->GetPri(); - } - - //------------------------------------------------------------------------------ - EOprtAssociativity GetAssociativity() const - { - if (m_pCallback.get()==nullptr || m_pCallback->GetCode()!=cmOPRT_BIN) - throw ParserError(ecINTERNAL_ERROR); - - return m_pCallback->GetAssociativity(); - } - - //------------------------------------------------------------------------------ - /** \brief Return the address of the callback function assoziated with - function and operator tokens. - - \return The pointer stored in #m_pTok. - \throw exception_type if token type is non of: -
    -
  • cmFUNC
  • -
  • cmSTRFUNC
  • -
  • cmPOSTOP
  • -
  • cmINFIXOP
  • -
  • cmOPRT_BIN
  • -
- \sa ECmdCode - */ - generic_fun_type GetFuncAddr() const - { - return (m_pCallback.get()) ? (generic_fun_type)m_pCallback->GetAddr() : nullptr; - } - - void* GetParam() const - { - return (m_pCallback.get()) ? m_pCallback->GetParam() : nullptr; - } - - //------------------------------------------------------------------------------ - /** \biref Get value of the token. - - Only applicable to variable and value tokens. - \throw exception_type if token is no value/variable token. - */ - TBase GetVal() const - { - switch (m_iCode) - { - case cmVAL: return m_fVal; - case cmVAR: return *((TBase*)m_pTok); - default: throw ParserError(ecVAL_EXPECTED); - } - } - - //------------------------------------------------------------------------------ - /** \brief Get address of a variable token. - - Valid only if m_iType==CmdVar. - \throw exception_type if token is no variable token. - */ - TBase* GetVar() const - { - if (m_iCode!=cmVAR) - throw ParserError(ecINTERNAL_ERROR); - - return (TBase*)m_pTok; - } - - //------------------------------------------------------------------------------ - /** \brief Return the number of function arguments. - - Valid only if m_iType==CmdFUNC. - */ - int GetArgCount() const - { - assert(m_pCallback.get()); - - if (!m_pCallback->GetAddr()) - throw ParserError(ecINTERNAL_ERROR); - - return m_pCallback->GetArgc(); - } - - //------------------------------------------------------------------------------ - /** \brief Return the token identifier. - - If #m_iType is cmSTRING the token identifier is the value of the string argument - for a string function. - \return #m_strTok - \throw nothrow - \sa m_strTok - */ - const TString& GetAsString() const - { - return m_strTok; - } - }; -} // namespace mu - -#endif diff --git a/Modules/gin/3rdparty/muParser/muParserTokenReader.cpp b/Modules/gin/3rdparty/muParser/muParserTokenReader.cpp deleted file mode 100755 index eb42935..0000000 --- a/Modules/gin/3rdparty/muParser/muParserTokenReader.cpp +++ /dev/null @@ -1,982 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2013 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -#include -#include -#include -#include -#include -#include - -#include "muParserTokenReader.h" -#include "muParserBase.h" - -/** \file - \brief This file contains the parser token reader implementation. -*/ - -#ifdef _WIN32 -#pragma warning(push) -#pragma warning(disable: 4310) -#endif - -#if __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#endif - -namespace mu -{ - - // Forward declaration - class ParserBase; - - //--------------------------------------------------------------------------- - /** \brief Copy constructor. - - \sa Assign - \throw nothrow - */ - ParserTokenReader::ParserTokenReader(const ParserTokenReader &a_Reader) - { - Assign(a_Reader); - } - - //--------------------------------------------------------------------------- - /** \brief Assignment operator. - - Self assignment will be suppressed otherwise #Assign is called. - - \param a_Reader Object to copy to this token reader. - \throw nothrow - */ - ParserTokenReader& ParserTokenReader::operator=(const ParserTokenReader &a_Reader) - { - if (&a_Reader!=this) - Assign(a_Reader); - - return *this; - } - - //--------------------------------------------------------------------------- - /** \brief Assign state of a token reader to this token reader. - - \param a_Reader Object from which the state should be copied. - \throw nothrow - */ - void ParserTokenReader::Assign(const ParserTokenReader &a_Reader) - { - m_pParser = a_Reader.m_pParser; - m_strFormula = a_Reader.m_strFormula; - m_iPos = a_Reader.m_iPos; - m_iSynFlags = a_Reader.m_iSynFlags; - - m_UsedVar = a_Reader.m_UsedVar; - m_pFunDef = a_Reader.m_pFunDef; - m_pConstDef = a_Reader.m_pConstDef; - m_pVarDef = a_Reader.m_pVarDef; - m_pStrVarDef = a_Reader.m_pStrVarDef; - m_pPostOprtDef = a_Reader.m_pPostOprtDef; - m_pInfixOprtDef = a_Reader.m_pInfixOprtDef; - m_pOprtDef = a_Reader.m_pOprtDef; - m_bIgnoreUndefVar = a_Reader.m_bIgnoreUndefVar; - m_vIdentFun = a_Reader.m_vIdentFun; - m_pFactory = a_Reader.m_pFactory; - m_pFactoryData = a_Reader.m_pFactoryData; - m_iBrackets = a_Reader.m_iBrackets; - m_cArgSep = a_Reader.m_cArgSep; - m_fZero = a_Reader.m_fZero; - m_lastTok = a_Reader.m_lastTok; - } - - //--------------------------------------------------------------------------- - /** \brief Constructor. - - Create a Token reader and bind it to a parser object. - - \pre [assert] a_pParser may not be NULL - \post #m_pParser==a_pParser - \param a_pParent Parent parser object of the token reader. - */ - ParserTokenReader::ParserTokenReader(ParserBase *a_pParent) - :m_pParser(a_pParent) - ,m_strFormula() - ,m_iPos(0) - ,m_iSynFlags(0) - ,m_bIgnoreUndefVar(false) - ,m_pFunDef(nullptr) - ,m_pPostOprtDef(nullptr) - ,m_pInfixOprtDef(nullptr) - ,m_pOprtDef(nullptr) - ,m_pConstDef(nullptr) - ,m_pStrVarDef(nullptr) - ,m_pVarDef(nullptr) - ,m_pFactory(nullptr) - ,m_pFactoryData(nullptr) - ,m_vIdentFun() - ,m_UsedVar() - ,m_fZero(0) - ,m_iBrackets(0) - ,m_lastTok() - ,m_cArgSep(',') - { - assert(m_pParser); - SetParent(m_pParser); - } - - //--------------------------------------------------------------------------- - /** \brief Create instance of a ParserTokenReader identical with this - and return its pointer. - - This is a factory method the calling function must take care of the object destruction. - - \return A new ParserTokenReader object. - \throw nothrow - */ - ParserTokenReader* ParserTokenReader::Clone(ParserBase *a_pParent) const - { - std::unique_ptr ptr(new ParserTokenReader(*this)); - ptr->SetParent(a_pParent); - return ptr.release(); - } - - //--------------------------------------------------------------------------- - ParserTokenReader::token_type& ParserTokenReader::SaveBeforeReturn(const token_type &tok) - { - m_lastTok = tok; - return m_lastTok; - } - - //--------------------------------------------------------------------------- - void ParserTokenReader::AddValIdent(identfun_type a_pCallback) - { - // Use push_front is used to give user defined callbacks a higher priority than - // the built in ones. Otherwise reading hex numbers would not work - // since the "0" in "0xff" would always be read first making parsing of - // the rest impossible. - // reference: - // http://sourceforge.net/projects/muparser/forums/forum/462843/topic/4824956 - m_vIdentFun.push_front(a_pCallback); - } - - //--------------------------------------------------------------------------- - void ParserTokenReader::SetVarCreator(facfun_type a_pFactory, void *pUserData) - { - m_pFactory = a_pFactory; - m_pFactoryData = pUserData; - } - - //--------------------------------------------------------------------------- - /** \brief Return the current position of the token reader in the formula string. - - \return #m_iPos - \throw nothrow - */ - int ParserTokenReader::GetPos() const - { - return m_iPos; - } - - //--------------------------------------------------------------------------- - /** \brief Return a reference to the formula. - - \return #m_strFormula - \throw nothrow - */ - const string_type& ParserTokenReader::GetExpr() const - { - return m_strFormula; - } - - //--------------------------------------------------------------------------- - /** \brief Return a map containing the used variables only. */ - varmap_type& ParserTokenReader::GetUsedVar() - { - return m_UsedVar; - } - - //--------------------------------------------------------------------------- - /** \brief Initialize the token Reader. - - Sets the formula position index to zero and set Syntax flags to default for initial formula parsing. - \pre [assert] triggered if a_szFormula==0 - */ - void ParserTokenReader::SetFormula(const string_type &a_strFormula) - { - m_strFormula = a_strFormula; - ReInit(); - } - - //--------------------------------------------------------------------------- - /** \brief Set Flag that controls behaviour in case of undefined variables being found. - - If true, the parser does not throw an exception if an undefined variable is found. - otherwise it does. This variable is used internally only! - It suppresses a "undefined variable" exception in GetUsedVar(). - Those function should return a complete list of variables including - those the are not defined by the time of it's call. - */ - void ParserTokenReader::IgnoreUndefVar(bool bIgnore) - { - m_bIgnoreUndefVar = bIgnore; - } - - //--------------------------------------------------------------------------- - /** \brief Reset the token reader to the start of the formula. - - The syntax flags will be reset to a value appropriate for the - start of a formula. - \post #m_iPos==0, #m_iSynFlags = noOPT | noBC | noPOSTOP | noSTR - \throw nothrow - \sa ESynCodes - */ - void ParserTokenReader::ReInit() - { - m_iPos = 0; - m_iSynFlags = sfSTART_OF_LINE; - m_iBrackets = 0; - m_UsedVar.clear(); - m_lastTok = token_type(); - } - - //--------------------------------------------------------------------------- - /** \brief Read the next token from the string. */ - ParserTokenReader::token_type ParserTokenReader::ReadNextToken() - { - assert(m_pParser); - - const char_type *szFormula = m_strFormula.c_str(); - token_type tok; - - // Ignore all non printable characters when reading the expression - while (szFormula[m_iPos]>0 && szFormula[m_iPos]<=0x20) - ++m_iPos; - - if ( IsEOF(tok) ) return SaveBeforeReturn(tok); // Check for end of formula - if ( IsOprt(tok) ) return SaveBeforeReturn(tok); // Check for user defined binary operator - if ( IsFunTok(tok) ) return SaveBeforeReturn(tok); // Check for function token - if ( IsBuiltIn(tok) ) return SaveBeforeReturn(tok); // Check built in operators / tokens - if ( IsArgSep(tok) ) return SaveBeforeReturn(tok); // Check for function argument separators - if ( IsValTok(tok) ) return SaveBeforeReturn(tok); // Check for values / constant tokens - if ( IsVarTok(tok) ) return SaveBeforeReturn(tok); // Check for variable tokens - if ( IsStrVarTok(tok) ) return SaveBeforeReturn(tok); // Check for string variables - if ( IsString(tok) ) return SaveBeforeReturn(tok); // Check for String tokens - if ( IsInfixOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators - if ( IsPostOpTok(tok) ) return SaveBeforeReturn(tok); // Check for unary operators - - // Check String for undefined variable token. Done only if a - // flag is set indicating to ignore undefined variables. - // This is a way to conditionally avoid an error if - // undefined variables occur. - // (The GetUsedVar function must suppress the error for - // undefined variables in order to collect all variable - // names including the undefined ones.) - if ( (m_bIgnoreUndefVar || m_pFactory) && IsUndefVarTok(tok) ) - return SaveBeforeReturn(tok); - - // Check for unknown token - // - // !!! From this point on there is no exit without an exception possible... - // - string_type strTok; - int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); - if (iEnd!=m_iPos) - Error(ecUNASSIGNABLE_TOKEN, m_iPos, strTok); - - Error(ecUNASSIGNABLE_TOKEN, m_iPos, m_strFormula.substr(m_iPos)); - return token_type(); // never reached - } - - //--------------------------------------------------------------------------- - void ParserTokenReader::SetParent(ParserBase *a_pParent) - { - m_pParser = a_pParent; - m_pFunDef = &a_pParent->m_FunDef; - m_pOprtDef = &a_pParent->m_OprtDef; - m_pInfixOprtDef = &a_pParent->m_InfixOprtDef; - m_pPostOprtDef = &a_pParent->m_PostOprtDef; - m_pVarDef = &a_pParent->m_VarDef; - m_pStrVarDef = &a_pParent->m_StrVarDef; - m_pConstDef = &a_pParent->m_ConstDef; - } - - //--------------------------------------------------------------------------- - /** \brief Extract all characters that belong to a certain charset. - - \param a_szCharSet [in] Const char array of the characters allowed in the token. - \param a_strTok [out] The string that consists entirely of characters listed in a_szCharSet. - \param a_iPos [in] Position in the string from where to start reading. - \return The Position of the first character not listed in a_szCharSet. - \throw nothrow - */ - int ParserTokenReader::ExtractToken(const char_type *a_szCharSet, - string_type &a_sTok, - int a_iPos) const - { - int iEnd = (int)m_strFormula.find_first_not_of(a_szCharSet, a_iPos); - - if (iEnd==(int)string_type::npos) - iEnd = (int)m_strFormula.length(); - - // Assign token string if there was something found - if (a_iPos!=iEnd) - a_sTok = string_type( m_strFormula.begin()+a_iPos, m_strFormula.begin()+iEnd); - - return iEnd; - } - - //--------------------------------------------------------------------------- - /** \brief Check Expression for the presence of a binary operator token. - - Userdefined binary operator "++" gives inconsistent parsing result for - the equations "a++b" and "a ++ b" if alphabetic characters are allowed - in operator tokens. To avoid this this function checks specifically - for operator tokens. - */ - int ParserTokenReader::ExtractOperatorToken(string_type &a_sTok, - int a_iPos) const - { - // Changed as per Issue 6: https://code.google.com/p/muparser/issues/detail?id=6 - int iEnd = (int)m_strFormula.find_first_not_of(m_pParser->ValidOprtChars(), a_iPos); - if (iEnd==(int)string_type::npos) - iEnd = (int)m_strFormula.length(); - - // Assign token string if there was something found - if (a_iPos!=iEnd) - { - a_sTok = string_type( m_strFormula.begin() + a_iPos, m_strFormula.begin() + iEnd); - return iEnd; - } - else - { - // There is still the chance of having to deal with an operator consisting exclusively - // of alphabetic characters. - return ExtractToken(MUP_CHARS, a_sTok, a_iPos); - } - } - - //--------------------------------------------------------------------------- - /** \brief Check if a built in operator or other token can be found - \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. - \return true if an operator token has been found. - */ - bool ParserTokenReader::IsBuiltIn(token_type &a_Tok) - { - const char_type **const pOprtDef = m_pParser->GetOprtDef(), - *const szFormula = m_strFormula.c_str(); - - // Compare token with function and operator strings - // check string for operator/function - for (int i=0; pOprtDef[i]; i++) - { - std::size_t len( std::char_traits::length(pOprtDef[i]) ); - if ( string_type(pOprtDef[i]) == string_type(szFormula + m_iPos, szFormula + m_iPos + len) ) - { - switch(i) - { - //case cmAND: - //case cmOR: - //case cmXOR: - case cmLAND: - case cmLOR: - case cmLT: - case cmGT: - case cmLE: - case cmGE: - case cmNEQ: - case cmEQ: - case cmADD: - case cmSUB: - case cmMUL: - case cmDIV: - case cmPOW: - case cmASSIGN: - //if (len!=sTok.length()) - // continue; - - // The assignment operator need special treatment - if (i==cmASSIGN && m_iSynFlags & noASSIGN) - Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); - - if (!m_pParser->HasBuiltInOprt()) continue; - if (m_iSynFlags & noOPT) - { - // Maybe its an infix operator not an operator - // Both operator types can share characters in - // their identifiers - if ( IsInfixOpTok(a_Tok) ) - return true; - - Error(ecUNEXPECTED_OPERATOR, m_iPos, pOprtDef[i]); - } - - m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE | noEND; - break; - - case cmBO: - if (m_iSynFlags & noBO) - Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); - - if (m_lastTok.GetCode()==cmFUNC) - m_iSynFlags = noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN | noIF | noELSE; - else - m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN| noIF | noELSE; - - ++m_iBrackets; - break; - - case cmBC: - if (m_iSynFlags & noBC) - Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); - - m_iSynFlags = noBO | noVAR | noVAL | noFUN | noINFIXOP | noSTR | noASSIGN; - - if (--m_iBrackets<0) - Error(ecUNEXPECTED_PARENS, m_iPos, pOprtDef[i]); - break; - - case cmELSE: - if (m_iSynFlags & noELSE) - Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); - - m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; - break; - - case cmIF: - if (m_iSynFlags & noIF) - Error(ecUNEXPECTED_CONDITIONAL, m_iPos, pOprtDef[i]); - - m_iSynFlags = noBC | noPOSTOP | noEND | noOPT | noIF | noELSE; - break; - - default: // The operator is listed in c_DefaultOprt, but not here. This is a bad thing... - Error(ecINTERNAL_ERROR); - } // switch operator id - - m_iPos += (int)len; - a_Tok.Set( (ECmdCode)i, pOprtDef[i] ); - return true; - } // if operator string found - } // end of for all operator strings - - return false; - } - - //--------------------------------------------------------------------------- - bool ParserTokenReader::IsArgSep(token_type &a_Tok) - { - const char_type* szFormula = m_strFormula.c_str(); - - if (szFormula[m_iPos]==m_cArgSep) - { - // copy the separator into null terminated string - char_type szSep[2]; - szSep[0] = m_cArgSep; - szSep[1] = 0; - - if (m_iSynFlags & noARG_SEP) - Error(ecUNEXPECTED_ARG_SEP, m_iPos, szSep); - - m_iSynFlags = noBC | noOPT | noEND | noARG_SEP | noPOSTOP | noASSIGN; - m_iPos++; - a_Tok.Set(cmARG_SEP, szSep); - return true; - } - - return false; - } - - //--------------------------------------------------------------------------- - /** \brief Check for End of Formula. - - \return true if an end of formula is found false otherwise. - \param a_Tok [out] If an eof is found the corresponding token will be stored there. - \throw nothrow - \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsString, IsInfixOpTok, IsPostOpTok - */ - bool ParserTokenReader::IsEOF(token_type &a_Tok) - { - const char_type* szFormula = m_strFormula.c_str(); - - // check for EOF - if ( !szFormula[m_iPos] /*|| szFormula[m_iPos] == '\n'*/) - { - if ( m_iSynFlags & noEND ) - Error(ecUNEXPECTED_EOF, m_iPos); - - if (m_iBrackets>0) - Error(ecMISSING_PARENS, m_iPos, _T(")")); - - m_iSynFlags = 0; - a_Tok.Set(cmEND); - return true; - } - - return false; - } - - //--------------------------------------------------------------------------- - /** \brief Check if a string position contains a unary infix operator. - \return true if a function token has been found false otherwise. - */ - bool ParserTokenReader::IsInfixOpTok(token_type &a_Tok) - { - string_type sTok; - int iEnd = ExtractToken(m_pParser->ValidInfixOprtChars(), sTok, m_iPos); - if (iEnd==m_iPos) - return false; - - // iterate over all postfix operator strings - funmap_type::const_reverse_iterator it = m_pInfixOprtDef->rbegin(); - for ( ; it!=m_pInfixOprtDef->rend(); ++it) - { - if (sTok.find(it->first)!=0) - continue; - - a_Tok.Set(it->second, it->first); - m_iPos += (int)it->first.length(); - - if (m_iSynFlags & noINFIXOP) - Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); - - m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; - return true; - } - - return false; - -/* - a_Tok.Set(item->second, sTok); - m_iPos = (int)iEnd; - - if (m_iSynFlags & noINFIXOP) - Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); - - m_iSynFlags = noPOSTOP | noINFIXOP | noOPT | noBC | noSTR | noASSIGN; - return true; -*/ - } - - //--------------------------------------------------------------------------- - /** \brief Check whether the token at a given position is a function token. - \param a_Tok [out] If a value token is found it will be placed here. - \throw ParserException if Syntaxflags do not allow a function at a_iPos - \return true if a function token has been found false otherwise. - \pre [assert] m_pParser!=0 - */ - bool ParserTokenReader::IsFunTok(token_type &a_Tok) - { - string_type strTok; - int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); - if (iEnd==m_iPos) - return false; - - funmap_type::const_iterator item = m_pFunDef->find(strTok); - if (item==m_pFunDef->end()) - return false; - - // Check if the next sign is an opening bracket - const char_type *szFormula = m_strFormula.c_str(); - if (szFormula[iEnd]!='(') - return false; - - a_Tok.Set(item->second, strTok); - - m_iPos = (int)iEnd; - if (m_iSynFlags & noFUN) - Error(ecUNEXPECTED_FUN, m_iPos-(int)a_Tok.GetAsString().length(), a_Tok.GetAsString()); - - m_iSynFlags = noANY ^ noBO; - return true; - } - - //--------------------------------------------------------------------------- - /** \brief Check if a string position contains a binary operator. - \param a_Tok [out] Operator token if one is found. This can either be a binary operator or an infix operator token. - \return true if an operator token has been found. - */ - bool ParserTokenReader::IsOprt(token_type &a_Tok) - { - const char_type *const szExpr = m_strFormula.c_str(); - string_type strTok; - - int iEnd = ExtractOperatorToken(strTok, m_iPos); - if (iEnd==m_iPos) - return false; - - // Check if the operator is a built in operator, if so ignore it here - const char_type **const pOprtDef = m_pParser->GetOprtDef(); - for (int i=0; m_pParser->HasBuiltInOprt() && pOprtDef[i]; ++i) - { - if (string_type(pOprtDef[i])==strTok) - return false; - } - - // Note: - // All tokens in oprt_bin_maptype are have been sorted by their length - // Long operators must come first! Otherwise short names (like: "add") that - // are part of long token names (like: "add123") will be found instead - // of the long ones. - // Length sorting is done with ascending length so we use a reverse iterator here. - funmap_type::const_reverse_iterator it = m_pOprtDef->rbegin(); - for ( ; it!=m_pOprtDef->rend(); ++it) - { - const string_type &sID = it->first; - if ( sID == string_type(szExpr + m_iPos, szExpr + m_iPos + sID.length()) ) - { - a_Tok.Set(it->second, strTok); - - // operator was found - if (m_iSynFlags & noOPT) - { - // An operator was found but is not expected to occur at - // this position of the formula, maybe it is an infix - // operator, not a binary operator. Both operator types - // can share characters in their identifiers. - if ( IsInfixOpTok(a_Tok) ) - return true; - else - { - // nope, no infix operator - return false; - //Error(ecUNEXPECTED_OPERATOR, m_iPos, a_Tok.GetAsString()); - } - - } - - m_iPos += (int)sID.length(); - m_iSynFlags = noBC | noOPT | noARG_SEP | noPOSTOP | noEND | noASSIGN; - return true; - } - } - - return false; - } - - //--------------------------------------------------------------------------- - /** \brief Check if a string position contains a unary post value operator. */ - bool ParserTokenReader::IsPostOpTok(token_type &a_Tok) - { - // Do not check for postfix operators if they are not allowed at - // the current expression index. - // - // This will fix the bug reported here: - // - // http://sourceforge.net/tracker/index.php?func=detail&aid=3343891&group_id=137191&atid=737979 - // - if (m_iSynFlags & noPOSTOP) - return false; - // - - // Tricky problem with equations like "3m+5": - // m is a postfix operator, + is a valid sign for postfix operators and - // for binary operators parser detects "m+" as operator string and - // finds no matching postfix operator. - // - // This is a special case so this routine slightly differs from the other - // token readers. - - // Test if there could be a postfix operator - string_type sTok; - int iEnd = ExtractToken(m_pParser->ValidOprtChars(), sTok, m_iPos); - if (iEnd==m_iPos) - return false; - - // iterate over all postfix operator strings - funmap_type::const_reverse_iterator it = m_pPostOprtDef->rbegin(); - for ( ; it!=m_pPostOprtDef->rend(); ++it) - { - if (sTok.find(it->first)!=0) - continue; - - a_Tok.Set(it->second, sTok); - m_iPos += (int)it->first.length(); - - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noSTR | noASSIGN; - return true; - } - - return false; - } - - //--------------------------------------------------------------------------- - /** \brief Check whether the token at a given position is a value token. - - Value tokens are either values or constants. - - \param a_Tok [out] If a value token is found it will be placed here. - \return true if a value token has been found. - */ - bool ParserTokenReader::IsValTok(token_type &a_Tok) - { - assert(m_pConstDef); - assert(m_pParser); - - string_type strTok; - value_type fVal(0); - int iEnd(0); - - // 2.) Check for user defined constant - // Read everything that could be a constant name - iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); - if (iEnd!=m_iPos) - { - valmap_type::const_iterator item = m_pConstDef->find(strTok); - if (item!=m_pConstDef->end()) - { - m_iPos = iEnd; - a_Tok.SetVal(item->second, strTok); - - if (m_iSynFlags & noVAL) - Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); - - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; - return true; - } - } - - SParam p; - p.id = -1; - p.param = nullptr; - - // 3.call the value recognition functions provided by the user - // Call user defined value recognition functions - std::list::const_iterator item = m_vIdentFun.begin(); - for (item = m_vIdentFun.begin(); item!=m_vIdentFun.end(); ++item) - { - int iStart = m_iPos; - if ( (*item)(p, m_strFormula.c_str() + m_iPos, &m_iPos, &fVal)==1 ) - { - // 2013-11-27 Issue 2: https://code.google.com/p/muparser/issues/detail?id=2 - strTok.assign(m_strFormula.c_str(), iStart, m_iPos-iStart); - - if (m_iSynFlags & noVAL) - Error(ecUNEXPECTED_VAL, m_iPos - (int)strTok.length(), strTok); - - a_Tok.SetVal(fVal, strTok); - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; - return true; - } - } - - return false; - } - - //--------------------------------------------------------------------------- - /** \brief Check wheter a token at a given position is a variable token. - \param a_Tok [out] If a variable token has been found it will be placed here. - \return true if a variable token has been found. - */ - bool ParserTokenReader::IsVarTok(token_type &a_Tok) - { - if (m_pVarDef->empty()) - return false; - - string_type strTok; - int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); - if (iEnd==m_iPos) - return false; - - varmap_type::const_iterator item = m_pVarDef->find(strTok); - if (item==m_pVarDef->end()) - return false; - - if (m_iSynFlags & noVAR) - Error(ecUNEXPECTED_VAR, m_iPos, strTok); - - m_pParser->OnDetectVar(&m_strFormula, m_iPos, iEnd); - - m_iPos = iEnd; - a_Tok.SetVar(item->second, strTok); - m_UsedVar[item->first] = item->second; // Add variable to used-var-list - - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR; - -// Zur Info hier die SynFlags von IsVal(): -// m_iSynFlags = noVAL | noVAR | noFUN | noBO | noINFIXOP | noSTR | noASSIGN; - return true; - } - - //--------------------------------------------------------------------------- - bool ParserTokenReader::IsStrVarTok(token_type &a_Tok) - { - if (!m_pStrVarDef || m_pStrVarDef->empty()) - return false; - - string_type strTok; - int iEnd = ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos); - if (iEnd==m_iPos) - return false; - - strmap_type::const_iterator item = m_pStrVarDef->find(strTok); - if (item==m_pStrVarDef->end()) - return false; - - if (m_iSynFlags & noSTR) - Error(ecUNEXPECTED_VAR, m_iPos, strTok); - - m_iPos = iEnd; - if (!m_pParser->m_vStringVarBuf.size()) - Error(ecINTERNAL_ERROR); - - a_Tok.SetString(m_pParser->m_vStringVarBuf[item->second], m_pParser->m_vStringVarBuf.size() ); - - m_iSynFlags = noANY ^ ( noBC | noOPT | noEND | noARG_SEP); - return true; - } - - - //--------------------------------------------------------------------------- - /** \brief Check wheter a token at a given position is an undefined variable. - - \param a_Tok [out] If a variable tom_pParser->m_vStringBufken has been found it will be placed here. - \return true if a variable token has been found. - \throw nothrow - */ - bool ParserTokenReader::IsUndefVarTok(token_type &a_Tok) - { - string_type strTok; - int iEnd( ExtractToken(m_pParser->ValidNameChars(), strTok, m_iPos) ); - if ( iEnd==m_iPos ) - return false; - - if (m_iSynFlags & noVAR) - { - // 20061021 added token string strTok instead of a_Tok.GetAsString() as the - // token identifier. - // related bug report: - // http://sourceforge.net/tracker/index.php?func=detail&aid=1578779&group_id=137191&atid=737979 - Error(ecUNEXPECTED_VAR, m_iPos - (int)a_Tok.GetAsString().length(), strTok); - } - - SParam p; - p.id = -1; - p.param = nullptr; - - // If a factory is available implicitely create new variables - if (m_pFactory) - { - value_type *fVar = m_pFactory(p, strTok.c_str(), m_pFactoryData); - a_Tok.SetVar(fVar, strTok ); - - // Do not use m_pParser->DefineVar( strTok, fVar ); - // in order to define the new variable, it will clear the - // m_UsedVar array which will kill previously defined variables - // from the list - // This is safe because the new variable can never override an existing one - // because they are checked first! - (*m_pVarDef)[strTok] = fVar; - m_UsedVar[strTok] = fVar; // Add variable to used-var-list - } - else - { - a_Tok.SetVar((value_type*)&m_fZero, strTok); - m_UsedVar[strTok] = nullptr; // Add variable to used-var-list - } - - m_iPos = iEnd; - - // Call the variable factory in order to let it define a new parser variable - m_iSynFlags = noVAL | noVAR | noFUN | noBO | noPOSTOP | noINFIXOP | noSTR; - return true; - } - - - //--------------------------------------------------------------------------- - /** \brief Check wheter a token at a given position is a string. - \param a_Tok [out] If a variable token has been found it will be placed here. - \return true if a string token has been found. - \sa IsOprt, IsFunTok, IsStrFunTok, IsValTok, IsVarTok, IsEOF, IsInfixOpTok, IsPostOpTok - \throw nothrow - */ - bool ParserTokenReader::IsString(token_type &a_Tok) - { - if (m_strFormula[m_iPos]!='"') - return false; - - string_type strBuf(&m_strFormula[m_iPos+1]); - std::size_t iEnd(0), iSkip(0); - - // parser over escaped '\"' end replace them with '"' - for(iEnd=(int)strBuf.find( _T("\"") ); iEnd!=0 && iEnd!=string_type::npos; iEnd=(int)strBuf.find( _T("\""), iEnd)) - { - if (strBuf[iEnd-1]!='\\') break; - strBuf.replace(iEnd-1, 2, _T("\"") ); - iSkip++; - } - - if (iEnd==string_type::npos) - Error(ecUNTERMINATED_STRING, m_iPos, _T("\"") ); - - string_type strTok(strBuf.begin(), strBuf.begin()+iEnd); - - if (m_iSynFlags & noSTR) - Error(ecUNEXPECTED_STR, m_iPos, strTok); - - m_pParser->m_vStringBuf.push_back(strTok); // Store string in internal buffer - a_Tok.SetString(strTok, m_pParser->m_vStringBuf.size()); - - m_iPos += (int)strTok.length() + 2 + (int)iSkip; // +2 for quotes; +iSkip for escape characters - m_iSynFlags = noANY ^ ( noARG_SEP | noBC | noOPT | noEND ); - - return true; - } - - //--------------------------------------------------------------------------- - /** \brief Create an error containing the parse error position. - - This function will create an Parser Exception object containing the error text and its position. - - \param a_iErrc [in] The error code of type #EErrorCodes. - \param a_iPos [in] The position where the error was detected. - \param a_strTok [in] The token string representation associated with the error. - \throw ParserException always throws thats the only purpose of this function. - */ - void ParserTokenReader::Error( EErrorCodes a_iErrc, - int a_iPos, - const string_type &a_sTok) const - { - m_pParser->Error(a_iErrc, a_iPos, a_sTok); - } - - //--------------------------------------------------------------------------- - void ParserTokenReader::SetArgSep(char_type cArgSep) - { - m_cArgSep = cArgSep; - } - - //--------------------------------------------------------------------------- - char_type ParserTokenReader::GetArgSep() const - { - return m_cArgSep; - } -} // namespace mu - -#ifdef _WIN32 -#pragma warning(pop) -#endif - -#if __clang__ -#pragma clang diagnostic pop -#endif diff --git a/Modules/gin/3rdparty/muParser/muParserTokenReader.h b/Modules/gin/3rdparty/muParser/muParserTokenReader.h deleted file mode 100755 index 7417518..0000000 --- a/Modules/gin/3rdparty/muParser/muParserTokenReader.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - __________ - _____ __ __\______ \_____ _______ ______ ____ _______ - / \ | | \| ___/\__ \ \_ __ \/ ___/_/ __ \\_ __ \ - | Y Y \| | /| | / __ \_| | \/\___ \ \ ___/ | | \/ - |__|_| /|____/ |____| (____ /|__| /____ > \___ >|__| - \/ \/ \/ \/ - Copyright (C) 2004-2013 Ingo Berg - - Permission is hereby granted, free of charge, to any person obtaining a copy of this - software and associated documentation files (the "Software"), to deal in the Software - without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or - substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT - NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef MU_PARSER_TOKEN_READER_H -#define MU_PARSER_TOKEN_READER_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "muParserDef.h" -#include "muParserToken.h" - -/** \file - \brief This file contains the parser token reader definition. -*/ - - -namespace mu -{ - // Forward declaration - class ParserBase; - - /** \brief Token reader for the ParserBase class. - - */ - class ParserTokenReader - { - private: - - typedef ParserToken token_type; - - public: - - ParserTokenReader(ParserBase *a_pParent); - ParserTokenReader* Clone(ParserBase *a_pParent) const; - - void AddValIdent(identfun_type a_pCallback); - void SetVarCreator(facfun_type a_pFactory, void *pUserData); - void SetFormula(const string_type &a_strFormula); - void SetArgSep(char_type cArgSep); - - int GetPos() const; - const string_type& GetExpr() const; - varmap_type& GetUsedVar(); - char_type GetArgSep() const; - - void IgnoreUndefVar(bool bIgnore); - void ReInit(); - token_type ReadNextToken(); - - private: - - /** \brief Syntax codes. - - The syntax codes control the syntax check done during the first time parsing of - the expression string. They are flags that indicate which tokens are allowed next - if certain tokens are identified. - */ - enum ESynCodes - { - noBO = 1 << 0, ///< to avoid i.e. "cos(7)(" - noBC = 1 << 1, ///< to avoid i.e. "sin)" or "()" - noVAL = 1 << 2, ///< to avoid i.e. "tan 2" or "sin(8)3.14" - noVAR = 1 << 3, ///< to avoid i.e. "sin a" or "sin(8)a" - noARG_SEP = 1 << 4, ///< to avoid i.e. ",," or "+," ... - noFUN = 1 << 5, ///< to avoid i.e. "sqrt cos" or "(1)sin" - noOPT = 1 << 6, ///< to avoid i.e. "(+)" - noPOSTOP = 1 << 7, ///< to avoid i.e. "(5!!)" "sin!" - noINFIXOP = 1 << 8, ///< to avoid i.e. "++4" "!!4" - noEND = 1 << 9, ///< to avoid unexpected end of formula - noSTR = 1 << 10, ///< to block numeric arguments on string functions - noASSIGN = 1 << 11, ///< to block assignment to constant i.e. "4=7" - noIF = 1 << 12, - noELSE = 1 << 13, - sfSTART_OF_LINE = noOPT | noBC | noPOSTOP | noASSIGN | noIF | noELSE | noARG_SEP, - noANY = ~0 ///< All of he above flags set - }; - - ParserTokenReader(const ParserTokenReader &a_Reader); - ParserTokenReader& operator=(const ParserTokenReader &a_Reader); - void Assign(const ParserTokenReader &a_Reader); - - void SetParent(ParserBase *a_pParent); - int ExtractToken(const char_type *a_szCharSet, - string_type &a_strTok, - int a_iPos) const; - int ExtractOperatorToken(string_type &a_sTok, int a_iPos) const; - - bool IsBuiltIn(token_type &a_Tok); - bool IsArgSep(token_type &a_Tok); - bool IsEOF(token_type &a_Tok); - bool IsInfixOpTok(token_type &a_Tok); - bool IsFunTok(token_type &a_Tok); - bool IsPostOpTok(token_type &a_Tok); - bool IsOprt(token_type &a_Tok); - bool IsValTok(token_type &a_Tok); - bool IsVarTok(token_type &a_Tok); - bool IsStrVarTok(token_type &a_Tok); - bool IsUndefVarTok(token_type &a_Tok); - bool IsString(token_type &a_Tok); - void Error(EErrorCodes a_iErrc, - int a_iPos = -1, - const string_type &a_sTok = string_type() ) const; - - token_type& SaveBeforeReturn(const token_type &tok); - - ParserBase *m_pParser; - string_type m_strFormula; - int m_iPos; - int m_iSynFlags; - bool m_bIgnoreUndefVar; - - const funmap_type *m_pFunDef; - const funmap_type *m_pPostOprtDef; - const funmap_type *m_pInfixOprtDef; - const funmap_type *m_pOprtDef; - const valmap_type *m_pConstDef; - const strmap_type *m_pStrVarDef; - varmap_type *m_pVarDef; ///< The only non const pointer to parser internals - facfun_type m_pFactory; - void *m_pFactoryData; - std::list m_vIdentFun; ///< Value token identification function - varmap_type m_UsedVar; - value_type m_fZero; ///< Dummy value of zero, referenced by undefined variables - int m_iBrackets; - token_type m_lastTok; - char_type m_cArgSep; ///< The character used for separating function arguments - }; -} // namespace mu - -#endif diff --git a/Modules/gin/README.md b/Modules/gin/README.md deleted file mode 100755 index 36b1ba8..0000000 --- a/Modules/gin/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# gin -Shared generic tools, utilities and UI classes diff --git a/Modules/gin/components/componentutils.h b/Modules/gin/components/componentutils.h deleted file mode 100755 index 93ff804..0000000 --- a/Modules/gin/components/componentutils.h +++ /dev/null @@ -1,20 +0,0 @@ -/*============================================================================== - - Copyright 2020 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -inline void addAndMakeVisible (Component& parent, Array children) -{ - for (auto child : children) - parent.addAndMakeVisible (child); -} - -inline void addAndMakeVisible (Component& parent, std::initializer_list children) -{ - for (auto child : children) - parent.addAndMakeVisible ( child ); -} diff --git a/Modules/gin/components/componentviewer.cpp b/Modules/gin/components/componentviewer.cpp deleted file mode 100755 index 3412190..0000000 --- a/Modules/gin/components/componentviewer.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/*============================================================================== - - Copyright 2019 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -Component* realGetComponent (Component& p, juce::Point screenPos) -{ - if (p.getScreenBounds().contains (screenPos)) - { - for (auto c : p.getChildren()) - if (auto r = realGetComponent (*c, screenPos)) - return r; - - return &p; - } - - return nullptr; -} - -Component* realGetComponentUnderMouse() -{ - auto mouse = Desktop::getInstance().getMainMouseSource(); - auto pos = mouse.getScreenPosition().toInt(); - - auto& desktop = Desktop::getInstance(); - - for (int i = desktop.getNumComponents(); --i >= 0;) - { - if (auto dtc = desktop.getComponent (i)) - if (dtc->isVisible()) - if (auto c = realGetComponent (*dtc, pos)) - return c; - } - - return {}; -} - -static String getClassName (Component* c) -{ - #if __clang__ || __GNUC__ - int status = 0; - if (char* demangled = abi::__cxa_demangle (typeid (*c).name(), nullptr, nullptr, &status)) - { - auto res = String (demangled); - free (demangled); - return res; - } - return {}; - #else - String res = typeid (*c).name(); - if (res.startsWith ("class ")) res = res.substring (6); - if (res.startsWith ("struct ")) res = res.substring (7); - return res; - #endif -} - -//============================================================================== -class ComponentViewer::Snapshot : public Component -{ -public: - void update (Component* c, juce::Point pos, int zoom_) - { - zoom = zoom_; - if (c != nullptr) - { - int w = getWidth() / zoom + 1; - int h = getHeight() / zoom + 1; - - auto root = c->getTopLevelComponent(); - auto rootPos = root->getLocalPoint (c, pos); - - auto disp = Desktop::getInstance().getDisplays().findDisplayForPoint (c->localPointToGlobal (pos)); - scale = float (disp.scale); - - image = root->createComponentSnapshot ({rootPos.getX() - w / 2, rootPos.getY() - h / 2, w, h}, false, scale); - image = image.rescaled (w * zoom, h * zoom, Graphics::lowResamplingQuality); - repaint(); - } - else - { - clear(); - } - } - - void clear() - { - image = {}; - repaint(); - } - - Colour getColourUnderMouse() - { - if (! image.isNull() && zoom > 0) - { - int w = getWidth() / zoom + 1; - int h = getHeight() / zoom + 1; - - int x = w / 2 * zoom; - int y = h / 2 * zoom; - - return image.getPixelAt (x, y); - } - return {}; - } - -private: - void paint (Graphics& g) override - { - if (! image.isNull() && zoom > 0 && scale != 0.0f) - { - g.drawImageAt (image, 0, 0); - - int w = getWidth() / zoom + 1; - int h = getHeight() / zoom + 1; - - Rectangle rc (w / 2 * zoom, h / 2 * zoom, int (zoom / scale), int (zoom / scale)); - - auto c = image.getPixelAt (rc.getX(), rc.getY()); - g.setColour (c.contrasting()); - g.drawRect (rc, 1); - } - } - - Image image; - int zoom = 10; - float scale = 1.0f; -}; - -//============================================================================== -class ComponentViewer::ContentComponent : public Component, - private Timer, - private Slider::Listener -{ -public: - ContentComponent (PropertiesFile& settings_) - : settings (settings_) - { - Font f (Font::getDefaultMonospacedFontName(), 12.0f, Font::plain); - - addAndMakeVisible (mouseDetails); - mouseDetails.setMultiLine (true, false); - mouseDetails.setFont (f); - mouseDetails.setReadOnly (true); - - addAndMakeVisible (componentDetails); - componentDetails.setFont (f); - componentDetails.setMultiLine (true, false); - componentDetails.setReadOnly (true); - - addAndMakeVisible (snapshotDetails); - snapshotDetails.setFont (f); - snapshotDetails.setReadOnly (true); - snapshotDetails.setJustification (Justification::centred); - - addAndMakeVisible (zoom); - zoom.setTextBoxStyle (Slider::NoTextBox, false, 0, 0); - zoom.setRange (1, 30, 1); - zoom.setValue (settings.getIntValue ("ginZoom", 10)); - zoom.addListener (this); - - addAndMakeVisible (snapshot); - - Desktop::getInstance().addGlobalMouseListener (this); - } - - ~ContentComponent() override - { - Desktop::getInstance().removeGlobalMouseListener (this); - } - - void resized() override - { - auto rc = getLocalBounds(); - - mouseDetails.setBounds (rc.removeFromTop (50)); - componentDetails.setBounds (rc.removeFromTop (int (rc.getHeight() * 0.4))); - - auto row = rc.removeFromTop (25); - int w = row.getWidth() / 3; - zoom.setBounds (row.removeFromLeft (w)); - snapshotDetails.setBounds (row.removeFromLeft (w)); - - snapshot.setBounds (rc); - } - - void mouseUp (const MouseEvent& ) override { updateComponentDetailsAsync(); } - void mouseDown (const MouseEvent& ) override { updateComponentDetailsAsync(); } - void mouseDrag (const MouseEvent& ) override { updateComponentDetailsAsync(); } - void mouseMove (const MouseEvent& ) override { updateComponentDetailsAsync(); } - - void updateComponentDetailsAsync() - { - if (! isTimerRunning()) - startTimer (50); - } - - void timerCallback() override - { - stopTimer(); - updateComponentDetails(); - } - - void sliderValueChanged (Slider*) override - { - settings.setValue ("ginZoom", int (zoom.getValue())); - updateComponentDetails(); - } - - void updateComponentDetails() - { - auto mouse = Desktop::getInstance().getMainMouseSource(); - - auto pos = mouse.getScreenPosition().toInt(); - - StringArray componentHierarchy; - String cursorPos, colourDetails; - - if (auto c = realGetComponentUnderMouse()) - { - snapshot.update (c, c->getLocalPoint (nullptr, pos), int (zoom.getValue())); - componentHierarchy = getComponentHierarchy (c); - - cursorPos += "Component: (" + c->getLocalPoint (nullptr, pos).toString() + ")\n"; - cursorPos += "Window: (" + c->getTopLevelComponent()->getLocalPoint (nullptr, pos).toString() + ")\n"; - - auto col = snapshot.getColourUnderMouse(); - colourDetails = col.toDisplayString (true); - } - else - { - snapshot.clear(); - } - - cursorPos += "Screen: (" + pos.toString() + ")"; - - mouseDetails.setText (cursorPos); - snapshotDetails.setText (colourDetails); - componentDetails.setText (componentHierarchy.joinIntoString ("\n")); - } - - StringArray getComponentHierarchy (Component* c) - { - StringArray res; - - while (c != nullptr) - { - String str; - - str += ("[" + String (getClassName (c)) + "]").paddedRight (' ', 60); - str += (" \"" + c->getName() + "\"").paddedRight (' ', 20); - str += (" (" + c->getBounds().toString() + ")").paddedRight (' ', 20); - str += String (c->isOpaque() ? " Opaque" : "").paddedRight (' ', 8); - str += String (c->isPaintingUnclipped() ? " Unclipped" : "").paddedRight (' ', 11); - - res.add (str); - - c = c->getParentComponent(); - } - return res; - } - - PropertiesFile& settings; - - TextEditor mouseDetails, componentDetails, snapshotDetails; - Slider zoom; - Snapshot snapshot; -}; - -//============================================================================== -ComponentViewer::ComponentViewer (Component* toTrack_, PropertiesFile* settings_, bool alwaysOnTop) - : DocumentWindow ("Component Viewer Window", Colours::white, allButtons, true), - toTrack (toTrack_) -{ - if (settings_ != nullptr) - { - settings.set (settings_, false); - } - else - { - PropertiesFile::Options opts; - - opts.applicationName = "Gin"; - opts.filenameSuffix = ".xml"; - opts.folderName = "Gin"; - opts.osxLibrarySubFolder = "Application Support"; - opts.commonToAllUsers = false; - opts.ignoreCaseOfKeyNames = false; - opts.doNotSave = false; - opts.millisecondsBeforeSaving = 1; - opts.storageFormat = juce::PropertiesFile::storeAsXML; - - settings.set (new PropertiesFile (opts), true); - } - - if (toTrack != nullptr) - toTrack->addComponentListener (this); - - auto position = settings->getValue ("ginComponentViewerPosition", ""); - - if (position.isNotEmpty()) - restoreWindowStateFromString (position); - else - centreWithSize (640, 480); - - setVisible (true); - setAlwaysOnTop (alwaysOnTop); - setResizable (true, false); - - setContentOwned (new ContentComponent (*settings), false); - - onClose = [this] { delete this; }; -} - -ComponentViewer::~ComponentViewer() -{ - if (toTrack != nullptr) - toTrack->removeComponentListener (this); - - saveWindowPosition(); -} - -void ComponentViewer::closeButtonPressed() -{ - if (onClose) - onClose(); -} - -void ComponentViewer::moved() -{ - DocumentWindow::resized(); - saveWindowPosition(); -} - -void ComponentViewer::resized() -{ - DocumentWindow::resized(); - saveWindowPosition(); -} - -void ComponentViewer::saveWindowPosition() -{ - if (settings != nullptr) - { - settings->setValue ("ginComponentViewerPosition", getWindowStateAsString()); - settings->saveIfNeeded(); - } -} - -void ComponentViewer::componentBeingDeleted (Component&) -{ - settings.reset(); - if (toTrack != nullptr) - toTrack = nullptr; - - delete this; -} - -void ComponentViewer::lookAndFeelChanged() -{ - auto& lf = getLookAndFeel (); - setBackgroundColour (lf.findColour (ResizableWindow::backgroundColourId)); -} diff --git a/Modules/gin/components/componentviewer.h b/Modules/gin/components/componentviewer.h deleted file mode 100755 index 6a1ff45..0000000 --- a/Modules/gin/components/componentviewer.h +++ /dev/null @@ -1,47 +0,0 @@ -/*============================================================================== - - Copyright 2019 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -//==============================================================================*/ - -/** Show the component under the mouse and component hierarchy. - Useful for debugging */ -class ComponentViewer : public DocumentWindow, - public ComponentListener -{ -public: - //==============================================================================*/ - /* Pass in a settings file to store window location, otherwise default file will - be used. Pass in a component to track and when this component is deleted, the - ComponentViewer will be deleted as well, or nullptr if you don't want this feature - */ - ComponentViewer (Component* toTrack = nullptr, PropertiesFile* settings = nullptr, bool alwaysOnTop = true); - ~ComponentViewer() override; - - /* User wants to close window, you should delete it. By default will delete itself */ - std::function onClose; - -private: - //==============================================================================*/ - void componentBeingDeleted (Component&) override; - void closeButtonPressed() override; - - void lookAndFeelChanged() override; - - void moved() override; - void resized() override; - - void saveWindowPosition(); - - class Snapshot; - class ContentComponent; - - //==============================================================================*/ - OptionalScopedPointer settings; - Component* toTrack = nullptr; -}; diff --git a/Modules/gin/components/ginlookandfeel.cpp b/Modules/gin/components/ginlookandfeel.cpp deleted file mode 100755 index 393e965..0000000 --- a/Modules/gin/components/ginlookandfeel.cpp +++ /dev/null @@ -1,193 +0,0 @@ - -//============================================================================== -GinLookAndFeel::GinLookAndFeel() -{ - setColour (GinLookAndFeel::colourId1, Colour (0xff020202)); - setColour (GinLookAndFeel::colourId2, Colour (0xff393d3f)); - setColour (GinLookAndFeel::colourId3, Colour (0xffc6c5b9)); - setColour (GinLookAndFeel::colourId4, Colour (0xfff4f4f9)); - setColour (GinLookAndFeel::colourId5, Colour (0xfffdfdff)); - - setColour (Label::textColourId, defaultColour (4).withAlpha (0.9f)); - - setColour (Slider::trackColourId, defaultColour (4)); - setColour (Slider::rotarySliderFillColourId, defaultColour (4)); - - setColour (TextButton::buttonColourId, defaultColour (0)); - setColour (TextButton::buttonOnColourId, defaultColour (4)); - setColour (TextButton::textColourOffId, defaultColour (4)); - setColour (TextButton::textColourOnId, defaultColour (0)); - - setColour (ComboBox::backgroundColourId, Colours::transparentWhite); - setColour (ComboBox::outlineColourId, defaultColour (4)); - - setColour (TextEditor::backgroundColourId, Colours::transparentWhite); - setColour (TextEditor::textColourId, defaultColour (4)); - setColour (TextEditor::highlightColourId, defaultColour (4)); - setColour (TextEditor::highlightedTextColourId, defaultColour (0)); - setColour (TextEditor::outlineColourId, defaultColour (4)); - setColour (TextEditor::focusedOutlineColourId, defaultColour (4)); - setColour (TextEditor::shadowColourId, Colours::transparentWhite); -} - -Colour GinLookAndFeel::defaultColour (int idx) -{ - switch (idx) - { - case 0: return findColour (GinLookAndFeel::colourId1); - case 1: return findColour (GinLookAndFeel::colourId2); - case 2: return findColour (GinLookAndFeel::colourId3); - case 3: return findColour (GinLookAndFeel::colourId4); - case 4: return findColour (GinLookAndFeel::colourId5); - } - return Colours::transparentWhite; -} - -void GinLookAndFeel::drawLinearSlider (Graphics& g, int x, int y, int width, int height, - float sliderPos, float /*minSliderPos*/, float /*maxSliderPos*/, - const Slider::SliderStyle, Slider& slider) -{ - const bool isMouseOver = slider.isMouseOverOrDragging() && slider.isEnabled(); - auto rc = Rectangle (x, y, width, height); - rc = rc.withSizeKeepingCentre (width, jmin (height, 4)); - - g.setColour (slider.findColour (Slider::trackColourId).withAlpha (0.1f)); - g.fillRect (rc); - - if (slider.isEnabled()) - g.setColour (slider.findColour (Slider::trackColourId).withAlpha (isMouseOver ? 0.95f : 0.85f)); - - if (slider.isHorizontal()) - g.fillRect (Rectangle (static_cast (rc.getX()), rc.getY() + 0.5f, sliderPos - rc.getX(), rc.getHeight() - 1.0f)); - else - g.fillRect (Rectangle (rc.getX() + 0.5f, sliderPos, rc.getWidth() - 1.0f, rc.getY() + (rc.getHeight() - sliderPos))); -} - -void GinLookAndFeel::drawRotarySlider (Graphics& g, int x, int y, int width, int height, float sliderPos, - const float rotaryStartAngleIn, const float rotaryEndAngle, Slider& slider) -{ - float rotaryStartAngle = rotaryStartAngleIn; - const float radius = jmin (width / 2, height / 2) - 2.0f; - const float centreX = x + width * 0.5f; - const float centreY = y + height * 0.5f; - const float rx = centreX - radius; - const float ry = centreY - radius; - const float rw = radius * 2.0f; - const float angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle); - const bool isMouseOver = slider.isMouseOverOrDragging() && slider.isEnabled(); - - const float thickness = (radius - 1) / radius; - - g.setColour (slider.findColour (Slider::rotarySliderFillColourId).withAlpha (0.1f)); - - { - Path filledArc; - filledArc.addPieSegment (rx, ry, rw, rw, rotaryStartAngle, rotaryEndAngle, thickness); - g.fillPath (filledArc); - } - - if (slider.isEnabled()) - g.setColour (slider.findColour (Slider::rotarySliderFillColourId).withAlpha (isMouseOver ? 0.95f : 0.85f)); - - auto fillStartAngle = rotaryStartAngle; - if (slider.getProperties().contains ("fromCentre")) - fillStartAngle = (rotaryStartAngle + rotaryEndAngle) / 2; - - { - Path filledArc; - filledArc.addPieSegment (rx, ry, rw, rw, fillStartAngle, angle, thickness); - g.fillPath (filledArc); - } - - if (slider.getProperties().contains ("modDepth")) - { - auto depth = (float)slider.getProperties()["modDepth"]; - bool bipolar = (bool)slider.getProperties()["modBipolar"]; - - g.setColour (Colours::red.withAlpha (0.8f)); - - Path filledArc; - if (bipolar) - { - auto a = jlimit (rotaryStartAngle, rotaryEndAngle, angle - depth * (rotaryEndAngle - rotaryStartAngle)); - auto b = jlimit (rotaryStartAngle, rotaryEndAngle, angle + depth * (rotaryEndAngle - rotaryStartAngle)); - filledArc.addPieSegment (rx, ry, rw, rw, std::min (a, b), std::max (a, b), thickness); - } - else - { - auto modPos = jlimit (rotaryStartAngle, rotaryEndAngle, angle + depth * (rotaryEndAngle - rotaryStartAngle)); - filledArc.addPieSegment (rx, ry, rw, rw, angle, modPos, thickness); - } - - g.fillPath (filledArc); - } - - if (slider.getProperties().contains ("modValues")) - { - g.setColour (Colours::red.withAlpha (0.8f)); - - auto varArray = slider.getProperties()["modValues"]; - if (varArray.isArray()) - { - for (auto value : *varArray.getArray()) - { - float modAngle = float (value) * (rotaryEndAngle - rotaryStartAngle) + rotaryStartAngle; - - float modX = centreX + std::sin (modAngle) * radius; - float modY = centreY - std::cos (modAngle) * radius; - - g.fillEllipse (modX - 2, modY - 2, 4.0f, 4.0f); - } - } - } -} - -void GinLookAndFeel::drawButtonBackground (Graphics& g, Button& b, const Colour&, - bool, bool) -{ - if (b.isMouseOver() && b.isEnabled()) - { - g.setColour (b.findColour (TextButton::buttonOnColourId).withMultipliedAlpha (0.2f)); - g.fillRect (b.getLocalBounds()); - } - - g.setColour (b.findColour (TextButton::buttonOnColourId).withMultipliedAlpha (b.isEnabled() ? 1.0f : 0.5f)); - if (b.getToggleState()) - g.fillRect (b.getLocalBounds()); - else - g.drawRect (b.getLocalBounds()); -} - -void GinLookAndFeel::drawButtonText (Graphics& g, TextButton& b, bool, bool) -{ - g.setFont (getTextButtonFont (b, b.getHeight())); - - g.setColour (b.findColour (b.getToggleState() ? TextButton::textColourOnId : TextButton::textColourOffId).withMultipliedAlpha (b.isEnabled() ? 1.0f : 0.5f)); - g.drawText (b.getButtonText(), b.getLocalBounds(), Justification::centred); -} - -void GinLookAndFeel::drawComboBox (Graphics& g, int width, int height, bool /*isButtonDown*/, - int /*buttonX*/, int /*buttonY*/, int /*buttonW*/, int /*buttonH*/, - ComboBox& box) -{ - const Rectangle boxBounds (0, 0, width, height); - - g.setColour (box.findColour (ComboBox::backgroundColourId)); - g.fillRect (boxBounds.toFloat()); - - g.setColour (box.findColour (ComboBox::outlineColourId)); - g.drawRect (boxBounds); -} - -void GinLookAndFeel::positionComboBoxText (ComboBox& box, Label& label) -{ - label.setBounds (1, 1, box.getWidth() - 1, box.getHeight() - 1); - label.setFont (getComboBoxFont (box)); - label.setJustificationType (Justification::centred); -} - -void GinLookAndFeel::drawTextEditorOutline (Graphics& g, int width, int height, TextEditor&) -{ - g.setColour (defaultColour (4)); - g.drawRect (0, 0, width, height); -} diff --git a/Modules/gin/components/ginlookandfeel.h b/Modules/gin/components/ginlookandfeel.h deleted file mode 100755 index 33dc5cb..0000000 --- a/Modules/gin/components/ginlookandfeel.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -//============================================================================== -class GinLookAndFeel : public LookAndFeel_V4 -{ -public: - GinLookAndFeel(); - - enum ColourIds - { - colourId1 = 0x8700001, - colourId2 = 0x8700002, - colourId3 = 0x8700003, - colourId4 = 0x8700004, - colourId5 = 0x8700005, - }; - - Colour defaultColour (int idx); - - void drawRotarySlider (Graphics&, int x, int y, int width, int height, - float sliderPosProportional, float rotaryStartAngle, float rotaryEndAngle, - Slider&) override; - - void drawLinearSlider (Graphics&, int x, int y, int width, int height, - float sliderPos, float minSliderPos, float maxSliderPos, - const Slider::SliderStyle, Slider&) override; - - - void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour, - bool isMouseOverButton, bool isButtonDown) override; - - void drawButtonText (Graphics&, TextButton&, bool isMouseOverButton, bool isButtonDown) override; - - void drawComboBox (Graphics&, int width, int height, bool isButtonDown, - int buttonX, int buttonY, int buttonW, int buttonH, - ComboBox&) override; - - void positionComboBoxText (ComboBox&, Label&) override; - - void drawTextEditorOutline (Graphics&, int width, int height, TextEditor&) override; -}; diff --git a/Modules/gin/components/mapviewer.cpp b/Modules/gin/components/mapviewer.cpp deleted file mode 100755 index 9d2ed1e..0000000 --- a/Modules/gin/components/mapviewer.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - - -MapViewer::MapViewer() - : zoom (14), - xoffset (0), - yoffset (0), - userAdjusted (false), - posMarker (juce::Point()) -{ - mapsize = osm->getMapWidthPixels(zoom); - - osm->addListener (this); - - centerOn (-123.41480970382690, 48.490145885498649); -} - -MapViewer::~MapViewer() -{ - osm->removeListener (this); - - clearDoubleBuffer(); -} - -void MapViewer::setZoom (int zoom_) -{ - zoom_ = jlimit (0, 18, zoom_); - if (zoom != zoom_) - { - zoom = zoom_; - mapsize = osm->getMapWidthPixels(zoom); - - osm->clearQueue(); - - mapUpdated(); - } -} - -void MapViewer::tileFetched (int zoom_, int x, int y) -{ - if (zoom == zoom_) - { - mapUpdated(); - repaint (x * 256 - xoffset, y * 256 - yoffset, 256, 256); - } -} - -void MapViewer::resized() -{ - centerOn (centerPt.getX(), centerPt.getY()); - - mapUpdated(); -} - -void MapViewer::paint (Graphics& g) -{ - updateDoubleBuffer(); - - if (doubleBuffer != nullptr) - g.drawImageAt (*doubleBuffer, 0, 0); -} - -void MapViewer::mouseDown (const MouseEvent& e) -{ - lastPos = e.getPosition(); -} - -void MapViewer::mouseDrag (const MouseEvent& e) -{ - userAdjusted = true; - - auto curPos = e.getPosition(); - - xoffset = jlimit (0, mapsize - getWidth(), xoffset - (curPos.getX() - lastPos.getX())); - yoffset = jlimit (0, mapsize - getHeight(), yoffset - (curPos.getY() - lastPos.getY())); - - centerPt = osm->displayToCoordinate (juce::Point(xoffset + getWidth() / 2, yoffset + getHeight() / 2), zoom); - - lastPos = curPos; - - mapUpdated(); -} - -void MapViewer::mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wheel) -{ - userAdjusted = true; - - wheelDelta += wheel.deltaY; - - if (std::abs (wheelDelta) > 0.1 || ! wheel.isSmooth) - { - wheelDelta = 0; - - juce::Point centerP = osm->displayToCoordinate (juce::Point (xoffset + e.x, yoffset + e.y), zoom); - - if (wheel.deltaY < 0) - setZoom (zoom - 1); - else - setZoom (zoom + 1); - - centerUnderPt (centerP, e.getPosition()); - } -} - -void MapViewer::centerOn (double longCenter, double latCenter) -{ - juce::Point p = osm->coordinateToDisplay(juce::Point(longCenter, latCenter), zoom); - - xoffset = jlimit (0, (mapsize - getWidth()), int (p.getX()) - getWidth() / 2); - yoffset = jlimit (0, (mapsize - getHeight()), int (p.getY()) - getHeight() / 2); - - centerPt = juce::Point(longCenter, latCenter); - - mapUpdated(); -} - -void MapViewer::centerUnderPt (juce::Point world, juce::Point view) -{ - juce::Point p = osm->coordinateToDisplay (world, zoom); - - xoffset = jlimit (0, jmax (1, (mapsize - getWidth())), int (p.getX()) - view.getX()); - yoffset = jlimit (0, jmax (1, (mapsize - getHeight())), int (p.getY()) - view.getY()); - - centerPt = osm->displayToCoordinate (juce::Point(xoffset + getWidth() / 2, yoffset + getHeight() / 2), zoom); - - repaint(); -} - -void MapViewer::updateDoubleBuffer() -{ - if (doubleBuffer) - return; - - Rectangle rc (0, 0, getWidth(), getHeight()); - doubleBuffer = std::make_unique (Image::ARGB, rc.getWidth(), rc.getHeight(), true); - - Graphics g (*doubleBuffer); - - // draw the map tiles - for (int x = (rc.getX() + xoffset) / 256 * 256; x <= rc.getRight() + xoffset; x += 256) - { - for (int y = (rc.getY() + yoffset) / 256 * 256; y <= rc.getBottom() + yoffset; y += 256) - { - Image tile = osm->fetchTile (zoom, x / 256, y / 256); - g.drawImageAt (tile, x - xoffset, y - yoffset); - } - } -} - -void MapViewer::clearDoubleBuffer() -{ - if (doubleBuffer) - doubleBuffer = nullptr; -} - -void MapViewer::mapUpdated() -{ - clearDoubleBuffer(); - repaint(); -} diff --git a/Modules/gin/components/mapviewer.h b/Modules/gin/components/mapviewer.h deleted file mode 100755 index 8670ace..0000000 --- a/Modules/gin/components/mapviewer.h +++ /dev/null @@ -1,62 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -//==============================================================================*/ -// Draws an OSM map -class MapViewer : public Component, - private OpenStreetMaps::Listener -{ -public: - MapViewer(); - ~MapViewer() override; - - void setZoom (int zoom); - void centerOn (double longCenter, double latCenter); - void centerUnderPt (juce::Point world, juce::Point view); - - OpenStreetMaps* getOpenStreetMaps() { return osm; } - -protected: - void resized() override; - void paint (Graphics& g) override; - void mouseDown (const MouseEvent& e) override; - void mouseDrag (const MouseEvent& e) override; - void mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wheel) override; - - void tileFetched (int zoom, int x, int y) override; - void updateMap(); - void mapUpdated(); - void preferencesChanged(); - void saveSnapshot(); - -private: - void updateDoubleBuffer(); - void clearDoubleBuffer(); - - int zoom; - int mapsize; - - int xoffset; - int yoffset; - - double wheelDelta = 0; - - SharedResourcePointer osm; - - juce::Point lastPos; - juce::Point centerPt; - - bool userAdjusted; - - juce::Point posMarker; - - std::unique_ptr doubleBuffer; - - -}; diff --git a/Modules/gin/components/propertycomponents.cpp b/Modules/gin/components/propertycomponents.cpp deleted file mode 100755 index 15149ec..0000000 --- a/Modules/gin/components/propertycomponents.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - - diff --git a/Modules/gin/components/propertycomponents.h b/Modules/gin/components/propertycomponents.h deleted file mode 100755 index 3896644..0000000 --- a/Modules/gin/components/propertycomponents.h +++ /dev/null @@ -1,154 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -//============================================================================== -class PropertyComponentBase : public PropertyComponent, - private Value::Listener -{ -public: - PropertyComponentBase (const Value& valueToControl, const String& propertyName) - : PropertyComponent (propertyName), value (valueToControl) - { - value.addListener (this); - } - -protected: - void valueChanged (Value&) override - { - refresh(); - } - - Value value; -}; - -//==============================================================================*/ -class FilePropertyComponent : public PropertyComponentBase -{ -public: - FilePropertyComponent (const Value& valueToControl, const String& propertyName, const String& title_ = "Open", const String pattern_ = "*.*") - : PropertyComponentBase (valueToControl, propertyName), title (title_), pattern (pattern_) - { - addAndMakeVisible (container); - - container.browse.onClick = [this] - { - FileChooser box (title, File (value.toString()), pattern); - - if (box.browseForFileToOpen()) - value.setValue (box.getResult().getFullPathName()); - }; - - container.clear.onClick = [this] { value.setValue (""); }; - } - - void refresh() override - { - container.filename.setText (value.toString()); - } - -private: - class Container : public Component - { - public: - Container() - { - addAndMakeVisible (filename); - addAndMakeVisible (browse); - addAndMakeVisible (clear); - - filename.setReadOnly (true); - } - - void resized() override - { - auto rc = getLocalBounds(); - clear.setBounds (rc.removeFromRight (rc.getHeight())); - browse.setBounds (rc.removeFromRight (rc.getHeight())); - rc.removeFromRight (3); - filename.setBounds (rc); - } - - TextEditor filename; - TextButton browse {"..."}; - TextButton clear {"X"}; - }; - - Container container; - - String title, pattern; -}; - -//==============================================================================*/ -class ColourPropertyComponent : public PropertyComponentBase -{ -public: - ColourPropertyComponent (const Value& valueToControl, const String& propertyName, bool showAlpha = false) - : PropertyComponentBase (valueToControl, propertyName), container (value, showAlpha) - { - addAndMakeVisible (container); - } - - void refresh() override - { - repaint(); - } - - void paint (Graphics& g) override - { - PropertyComponent::paint (g); - - g.setColour (findColour (BooleanPropertyComponent::backgroundColourId)); - g.fillRect (container.getBounds()); - - g.setColour (findColour (BooleanPropertyComponent::outlineColourId)); - g.drawRect (container.getBounds()); - } - -private: - class Container : public Component - { - public: - Container (Value& value_, bool a) - : value (value_), alpha (a) - { - } - - void paint (Graphics& g) override - { - Colour c = Colour::fromString (value.toString()); - - g.setColour (c); - g.fillRect (getLocalBounds().reduced (4)); - - g.setColour (c.contrasting()); - g.drawText (c.toDisplayString (alpha), getLocalBounds(), Justification::centred); - } - - void mouseUp (const MouseEvent& e) override - { - if (e.mouseWasClicked()) - { - ColourSelector colourSelector (ColourSelector::showColourAtTop | ColourSelector::showSliders | ColourSelector::showColourspace); - - colourSelector.setSize (300, 280); - colourSelector.setCurrentColour (Colour::fromString (value.toString()), dontSendNotification); - - CallOutBox callOut (colourSelector, getScreenBounds(), nullptr); - callOut.runModalLoop(); - - value = colourSelector.getCurrentColour().toString(); - } - } - - Value& value; - bool alpha; - }; - - Container container; -}; diff --git a/Modules/gin/components/singlelinetexteditor.cpp b/Modules/gin/components/singlelinetexteditor.cpp deleted file mode 100755 index 6107436..0000000 --- a/Modules/gin/components/singlelinetexteditor.cpp +++ /dev/null @@ -1,2214 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2015 - ROLI Ltd. - - Permission is granted to use this software under the terms of either: - a) the GPL v2 (or any later version) - b) the Affero GPL v3 - - Details of these licenses can be found at: www.gnu.org/licenses - - JUCE is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - ------------------------------------------------------------------------------ - - To release a closed-source product which uses JUCE, commercial licenses are - available: visit www.juce.com for more information. - - ============================================================================== -*/ - -#include "singlelinetexteditor.h" - -// a word or space that can't be broken down any further -struct TextAtom -{ - //============================================================================== - String atomText; - float width; - int numChars; - - //============================================================================== - bool isWhitespace() const noexcept { return CharacterFunctions::isWhitespace (atomText[0]); } - bool isNewLine() const noexcept { return atomText[0] == '\r' || atomText[0] == '\n'; } - - String getText () const - { - return atomText; - } - - String getTrimmedText () const - { - return atomText.substring (0, numChars); - } - - JUCE_LEAK_DETECTOR (TextAtom) -}; - -//============================================================================== -// a run of text with a single font and colour -class SingleLineTextEditor::UniformTextSection -{ -public: - UniformTextSection (const String& text, const Font& f, Colour col) - : font (f), colour (col) - { - initialiseAtoms (text); - } - - UniformTextSection (const UniformTextSection& other) - : font (other.font), colour (other.colour) - { - atoms.addCopiesOf (other.atoms); - } - - void append (UniformTextSection& other) - { - if (other.atoms.size() > 0) - { - int i = 0; - - if (TextAtom* const lastAtom = atoms.getLast()) - { - if (! CharacterFunctions::isWhitespace (lastAtom->atomText.getLastCharacter())) - { - TextAtom* const first = other.atoms.getUnchecked(0); - - if (! CharacterFunctions::isWhitespace (first->atomText[0])) - { - lastAtom->atomText += first->atomText; - lastAtom->numChars = (uint16) (lastAtom->numChars + first->numChars); - lastAtom->width = font.getStringWidthFloat (lastAtom->getText()); - delete first; - ++i; - } - } - } - - atoms.ensureStorageAllocated (atoms.size() + other.atoms.size() - i); - - while (i < other.atoms.size()) - { - atoms.add (other.atoms.getUnchecked(i)); - ++i; - } - - other.atoms.clear (false); - } - } - - UniformTextSection* split (const int indexToBreakAt) - { - UniformTextSection* const section2 = new UniformTextSection (String(), font, colour); - int index = 0; - - for (int i = 0; i < atoms.size(); ++i) - { - TextAtom* const atom = atoms.getUnchecked(i); - - const int nextIndex = index + atom->numChars; - - if (index == indexToBreakAt) - { - for (int j = i; j < atoms.size(); ++j) - section2->atoms.add (atoms.getUnchecked (j)); - - atoms.removeRange (i, atoms.size(), false); - break; - } - else if (indexToBreakAt >= index && indexToBreakAt < nextIndex) - { - TextAtom* const secondAtom = new TextAtom(); - - secondAtom->atomText = atom->atomText.substring (indexToBreakAt - index); - secondAtom->width = font.getStringWidthFloat (secondAtom->getText()); - secondAtom->numChars = (uint16) secondAtom->atomText.length(); - - section2->atoms.add (secondAtom); - - atom->atomText = atom->atomText.substring (0, indexToBreakAt - index); - atom->width = font.getStringWidthFloat (atom->getText()); - atom->numChars = (uint16) (indexToBreakAt - index); - - for (int j = i + 1; j < atoms.size(); ++j) - section2->atoms.add (atoms.getUnchecked (j)); - - atoms.removeRange (i + 1, atoms.size(), false); - break; - } - - index = nextIndex; - } - - return section2; - } - - void appendAllText (MemoryOutputStream& mo) const - { - for (int i = 0; i < atoms.size(); ++i) - mo << atoms.getUnchecked(i)->atomText; - } - - void appendSubstring (MemoryOutputStream& mo, const Range range) const - { - int index = 0; - for (int i = 0; i < atoms.size(); ++i) - { - const TextAtom* const atom = atoms.getUnchecked (i); - const int nextIndex = index + atom->numChars; - - if (range.getStart() < nextIndex) - { - if (range.getEnd() <= index) - break; - - const Range r ((range - index).getIntersectionWith (Range (0, (int) atom->numChars))); - - if (! r.isEmpty()) - mo << atom->atomText.substring (r.getStart(), r.getEnd()); - } - - index = nextIndex; - } - } - - int getTotalLength() const noexcept - { - int total = 0; - - for (int i = atoms.size(); --i >= 0;) - total += atoms.getUnchecked(i)->numChars; - - return total; - } - - void setFont (const Font& newFont) - { - if (font != newFont) - { - font = newFont; - - for (int i = atoms.size(); --i >= 0;) - { - TextAtom* const atom = atoms.getUnchecked(i); - atom->width = newFont.getStringWidthFloat (atom->getText()); - } - } - } - - //============================================================================== - Font font; - Colour colour; - OwnedArray atoms; - -private: - void initialiseAtoms (const String& textToParse) - { - String::CharPointerType text (textToParse.getCharPointer()); - - while (! text.isEmpty()) - { - size_t numChars = 0; - String::CharPointerType start (text); - - // create a whitespace atom unless it starts with non-ws - if (text.isWhitespace() && *text != '\r' && *text != '\n') - { - do - { - ++text; - ++numChars; - } - while (text.isWhitespace() && *text != '\r' && *text != '\n'); - } - else - { - if (*text == '\r') - { - ++text; - ++numChars; - - if (*text == '\n') - { - ++start; - ++text; - } - } - else if (*text == '\n') - { - ++text; - ++numChars; - } - else - { - while (! (text.isEmpty() || text.isWhitespace())) - { - ++text; - ++numChars; - } - } - } - - TextAtom* const atom = atoms.add (new TextAtom()); - - atom->atomText = String (start, numChars); - atom->width = font.getStringWidthFloat (atom->getText()); - atom->numChars = (uint16) numChars; - } - } - - UniformTextSection& operator= (const UniformTextSection&); - JUCE_LEAK_DETECTOR (UniformTextSection) -}; - -//============================================================================== -class SingleLineTextEditor::Iterator -{ -public: - Iterator (const OwnedArray& sectionList, - const float wrapWidth, Justification j) - : indexInText (0), - lineY (0), - lineHeight (0), - maxDescent (0), - atomX (0), - atomRight (0), - atom (nullptr), - currentSection (nullptr), - justification (j), - sections (sectionList), - sectionIndex (0), - atomIndex (0), - wordWrapWidth (wrapWidth) - { - jassert (wordWrapWidth > 0); - - if (sections.size() > 0) - { - currentSection = sections.getUnchecked (sectionIndex); - - if (currentSection != nullptr) - beginNewLine(); - } - } - - Iterator (const Iterator& other) - : indexInText (other.indexInText), - lineY (other.lineY), - lineHeight (other.lineHeight), - maxDescent (other.maxDescent), - atomX (other.atomX), - atomRight (other.atomRight), - atom (other.atom), - currentSection (other.currentSection), - justification (other.justification), - sections (other.sections), - sectionIndex (other.sectionIndex), - atomIndex (other.atomIndex), - wordWrapWidth (other.wordWrapWidth), - tempAtom (other.tempAtom) - { - } - - //============================================================================== - bool next() - { - if (atom == &tempAtom) - { - const int numRemaining = tempAtom.atomText.length() - tempAtom.numChars; - - if (numRemaining > 0) - { - tempAtom.atomText = tempAtom.atomText.substring (tempAtom.numChars); - - atomX = 0; - - if (tempAtom.numChars > 0) - lineY += lineHeight; - - indexInText += tempAtom.numChars; - - GlyphArrangement g; - g.addLineOfText (currentSection->font, atom->getText(), 0.0f, 0.0f); - - int split; - for (split = 0; split < g.getNumGlyphs(); ++split) - if (shouldWrap (g.getGlyph (split).getRight())) - break; - - if (split > 0 && split <= numRemaining) - { - tempAtom.numChars = (uint16) split; - tempAtom.width = g.getGlyph (split - 1).getRight(); - atomRight = atomX + tempAtom.width; - return true; - } - } - } - - bool forceNewLine = false; - - if (sectionIndex >= sections.size()) - { - moveToEndOfLastAtom(); - return false; - } - else if (atomIndex >= currentSection->atoms.size() - 1) - { - if (atomIndex >= currentSection->atoms.size()) - { - if (++sectionIndex >= sections.size()) - { - moveToEndOfLastAtom(); - return false; - } - - atomIndex = 0; - currentSection = sections.getUnchecked (sectionIndex); - } - else - { - const TextAtom* const lastAtom = currentSection->atoms.getUnchecked (atomIndex); - - if (! lastAtom->isWhitespace()) - { - // handle the case where the last atom in a section is actually part of the same - // word as the first atom of the next section... - float right = atomRight + lastAtom->width; - float lineHeight2 = lineHeight; - float maxDescent2 = maxDescent; - - for (int section = sectionIndex + 1; section < sections.size(); ++section) - { - const UniformTextSection* const s = sections.getUnchecked (section); - - if (s->atoms.size() == 0) - break; - - const TextAtom* const nextAtom = s->atoms.getUnchecked (0); - - if (nextAtom->isWhitespace()) - break; - - right += nextAtom->width; - - lineHeight2 = jmax (lineHeight2, s->font.getHeight()); - maxDescent2 = jmax (maxDescent2, s->font.getDescent()); - - if (shouldWrap (right)) - { - lineHeight = lineHeight2; - maxDescent = maxDescent2; - - forceNewLine = true; - break; - } - - if (s->atoms.size() > 1) - break; - } - } - } - } - - if (atom != nullptr) - { - atomX = atomRight; - indexInText += atom->numChars; - - if (atom->isNewLine()) - beginNewLine(); - } - - atom = currentSection->atoms.getUnchecked (atomIndex); - atomRight = atomX + atom->width; - ++atomIndex; - - if (shouldWrap (atomRight) || forceNewLine) - { - if (atom->isWhitespace()) - { - // leave whitespace at the end of a line, but truncate it to avoid scrolling - atomRight = jmin (atomRight, wordWrapWidth); - } - else - { - atomRight = atom->width; - - if (shouldWrap (atomRight)) // atom too big to fit on a line, so break it up.. - { - tempAtom = *atom; - tempAtom.width = 0; - tempAtom.numChars = 0; - atom = &tempAtom; - - if (atomX > 0) - beginNewLine(); - - return next(); - } - - beginNewLine(); - return true; - } - } - - return true; - } - - void beginNewLine() - { - atomX = 0; - lineY += lineHeight; - - int tempSectionIndex = sectionIndex; - int tempAtomIndex = atomIndex; - const UniformTextSection* section = sections.getUnchecked (tempSectionIndex); - - lineHeight = section->font.getHeight(); - maxDescent = section->font.getDescent(); - - float x = (atom != nullptr) ? atom->width : 0; - - while (! shouldWrap (x)) - { - if (tempSectionIndex >= sections.size()) - break; - - bool checkSize = false; - - if (tempAtomIndex >= section->atoms.size()) - { - if (++tempSectionIndex >= sections.size()) - break; - - tempAtomIndex = 0; - section = sections.getUnchecked (tempSectionIndex); - checkSize = true; - } - - const TextAtom* const nextAtom = section->atoms.getUnchecked (tempAtomIndex); - - if (nextAtom == nullptr) - break; - - x += nextAtom->width; - - if (shouldWrap (x) || nextAtom->isNewLine()) - break; - - if (checkSize) - { - lineHeight = jmax (lineHeight, section->font.getHeight()); - maxDescent = jmax (maxDescent, section->font.getDescent()); - } - - ++tempAtomIndex; - } - } - - //============================================================================== - void draw (Graphics& g, const UniformTextSection*& lastSection) const - { - if (! atom->isWhitespace()) - { - if (lastSection != currentSection) - { - lastSection = currentSection; - g.setColour (currentSection->colour); - g.setFont (currentSection->font); - } - - jassert (atom->getTrimmedText().isNotEmpty()); - - GlyphArrangement ga; - ga.addJustifiedText (currentSection->font, atom->getTrimmedText(), - atomX, lineY + lineHeight - maxDescent, 100.0f, justification); - - ga.draw (g); - } - } - - void addSelection (RectangleList& area, const Range selected) const - { - const float startX = indexToX (selected.getStart()); - const float endX = indexToX (selected.getEnd()); - - area.add (startX, lineY, endX - startX, lineHeight); - } - - void drawUnderline (Graphics& g, const Range underline, const Colour colour) const - { - const int startX = roundToInt (indexToX (underline.getStart())); - const int endX = roundToInt (indexToX (underline.getEnd())); - const int baselineY = roundToInt (lineY + currentSection->font.getAscent() + 0.5f); - - Graphics::ScopedSaveState state (g); - g.reduceClipRegion (Rectangle (startX, baselineY, endX - startX, 1)); - g.fillCheckerBoard (Rectangle (endX, baselineY + 1).toFloat(), 3, 1, colour, Colours::transparentBlack); - } - - void drawSelectedText (Graphics& g, - const Range selected, - const Colour selectedTextColour) const - { - if (! atom->isWhitespace()) - { - GlyphArrangement ga; - ga.addLineOfText (currentSection->font, - atom->getTrimmedText(), - atomX, (float) roundToInt (lineY + lineHeight - maxDescent)); - - if (selected.getEnd() < indexInText + atom->numChars) - { - GlyphArrangement ga2 (ga); - ga2.removeRangeOfGlyphs (0, selected.getEnd() - indexInText); - ga.removeRangeOfGlyphs (selected.getEnd() - indexInText, -1); - - g.setColour (currentSection->colour); - ga2.draw (g); - } - - if (selected.getStart() > indexInText) - { - GlyphArrangement ga2 (ga); - ga2.removeRangeOfGlyphs (selected.getStart() - indexInText, -1); - ga.removeRangeOfGlyphs (0, selected.getStart() - indexInText); - - g.setColour (currentSection->colour); - ga2.draw (g); - } - - g.setColour (selectedTextColour); - ga.draw (g); - } - } - - //============================================================================== - float indexToX (const int indexToFind) const - { - if (indexToFind <= indexInText) - return atomX; - - if (indexToFind >= indexInText + atom->numChars) - return atomRight; - - GlyphArrangement g; - g.addLineOfText (currentSection->font, - atom->getText(), - atomX, 0.0f); - - if (indexToFind - indexInText >= g.getNumGlyphs()) - return atomRight; - - return jmin (atomRight, g.getGlyph (indexToFind - indexInText).getLeft()); - } - - int xToIndex (const float xToFind) const - { - if (xToFind <= atomX || atom->isNewLine()) - return indexInText; - - if (xToFind >= atomRight) - return indexInText + atom->numChars; - - GlyphArrangement g; - g.addLineOfText (currentSection->font, - atom->getText(), - atomX, 0.0f); - - const int numGlyphs = g.getNumGlyphs(); - - int j; - for (j = 0; j < numGlyphs; ++j) - { - const PositionedGlyph& pg = g.getGlyph(j); - if ((pg.getLeft() + pg.getRight()) / 2 > xToFind) - break; - } - - return indexInText + j; - } - - //============================================================================== - bool getCharPosition (const int index, float& cx, float& cy, float& lineHeightFound) - { - while (next()) - { - if (indexInText + atom->numChars > index) - { - cx = indexToX (index); - cy = lineY; - lineHeightFound = lineHeight; - return true; - } - } - - cx = atomX; - cy = lineY; - lineHeightFound = lineHeight; - return false; - } - - //============================================================================== - int indexInText; - float lineY, lineHeight, maxDescent; - float atomX, atomRight; - const TextAtom* atom; - const UniformTextSection* currentSection; - Justification justification; - -private: - const OwnedArray& sections; - int sectionIndex, atomIndex; - const float wordWrapWidth; - TextAtom tempAtom; - - Iterator& operator= (const Iterator&); - - void moveToEndOfLastAtom() - { - if (atom != nullptr) - { - atomX = atomRight; - - if (atom->isNewLine()) - { - atomX = 0.0f; - lineY += lineHeight; - } - } - } - - bool shouldWrap (const float x) const noexcept - { - return (x - 0.0001f) >= wordWrapWidth; - } - - JUCE_LEAK_DETECTOR (Iterator) -}; - - -//============================================================================== -class SingleLineTextEditor::InsertAction : public UndoableAction -{ -public: - InsertAction (SingleLineTextEditor& ed, - const String& newText, - const int insertPos, - const Font& newFont, - const Colour newColour, - const int oldCaret, - const int newCaret) - : owner (ed), - text (newText), - insertIndex (insertPos), - oldCaretPos (oldCaret), - newCaretPos (newCaret), - font (newFont), - colour (newColour) - { - } - - bool perform() override - { - owner.insert (text, insertIndex, font, colour, nullptr, newCaretPos); - return true; - } - - bool undo() override - { - owner.remove (Range (insertIndex, insertIndex + text.length()), nullptr, oldCaretPos); - return true; - } - - int getSizeInUnits() override - { - return text.length() + 16; - } - -private: - SingleLineTextEditor& owner; - const String text; - const int insertIndex, oldCaretPos, newCaretPos; - const Font font; - const Colour colour; - - JUCE_DECLARE_NON_COPYABLE (InsertAction) -}; - -//============================================================================== -class SingleLineTextEditor::RemoveAction : public UndoableAction -{ -public: - RemoveAction (SingleLineTextEditor& ed, - const Range rangeToRemove, - const int oldCaret, - const int newCaret, - const Array& oldSections) - : owner (ed), - range (rangeToRemove), - oldCaretPos (oldCaret), - newCaretPos (newCaret) - { - removedSections.addArray (oldSections); - } - - bool perform() override - { - owner.remove (range, nullptr, newCaretPos); - return true; - } - - bool undo() override - { - owner.reinsert (range.getStart(), removedSections); - owner.moveCaretTo (oldCaretPos, false); - return true; - } - - int getSizeInUnits() override - { - int n = 16; - for (int i = removedSections.size(); --i >= 0;) - n += removedSections.getUnchecked (i)->getTotalLength(); - - return n; - } - -private: - SingleLineTextEditor& owner; - const Range range; - const int oldCaretPos, newCaretPos; - OwnedArray removedSections; - - JUCE_DECLARE_NON_COPYABLE (RemoveAction) -}; - -//============================================================================== -class SingleLineTextEditor::TextHolderComponent : public Component, - public Timer, - public Value::Listener -{ -public: - TextHolderComponent (SingleLineTextEditor& ed) : owner (ed) - { - setWantsKeyboardFocus (false); - setInterceptsMouseClicks (false, true); - setMouseCursor (MouseCursor::ParentCursor); - - owner.getTextValue().addListener (this); - } - - ~TextHolderComponent() override - { - owner.getTextValue().removeListener (this); - } - - void paint (Graphics& g) override - { - owner.drawContent (g); - } - - void restartTimer() - { - startTimer (350); - } - - void timerCallback() override - { - owner.timerCallbackInt(); - } - - void valueChanged (Value&) override - { - owner.textWasChangedByValue(); - } - -private: - SingleLineTextEditor& owner; - - JUCE_DECLARE_NON_COPYABLE (TextHolderComponent) -}; - -//============================================================================== -namespace TextEditorDefs -{ - const int textChangeMessageId = 0x10003001; - const int returnKeyMessageId = 0x10003002; - const int escapeKeyMessageId = 0x10003003; - const int focusLossMessageId = 0x10003004; - - const int maxActionsPerTransaction = 100; - - static int getCharacterCategory (const juce_wchar character) - { - return CharacterFunctions::isLetterOrDigit (character) - ? 2 : (CharacterFunctions::isWhitespace (character) ? 0 : 1); - } -} - -//============================================================================== -SingleLineTextEditor::SingleLineTextEditor (const String& name) - : Component (name), - readOnly (false), - caretVisible (true), - popupMenuEnabled (true), - selectAllTextWhenFocused (false), - wasFocused (false), - tabKeyUsed (false), - menuActive (false), - valueTextNeedsUpdating (false), - consumeEscAndReturnKeys (true), - lastTransactionTime (0), - currentFont (14.0f), - totalNumChars (0), - caretPosition (0), - keyboardType (TextInputTarget::textKeyboard), - dragType (notDragging) -{ - setOpaque (true); - setMouseCursor (MouseCursor::IBeamCursor); - - textHolder = std::make_unique (*this); - addAndMakeVisible (*textHolder); - - setWantsKeyboardFocus (true); - recreateCaret(); -} - -SingleLineTextEditor::~SingleLineTextEditor() -{ - if (wasFocused) - if (ComponentPeer* const peer = getPeer()) - peer->dismissPendingTextInput(); - - textValue.removeListener (textHolder.get()); - textValue.referTo (Value()); - - textHolder = nullptr; -} - -//============================================================================== -void SingleLineTextEditor::newTransaction() -{ - lastTransactionTime = Time::getApproximateMillisecondCounter(); - undoManager.beginNewTransaction(); -} - -bool SingleLineTextEditor::undoOrRedo (const bool shouldUndo) -{ - if (! isReadOnly()) - { - newTransaction(); - - if (shouldUndo ? undoManager.undo() - : undoManager.redo()) - { - repaint(); - textChanged(); - return true; - } - } - - return false; -} - -bool SingleLineTextEditor::undo() { return undoOrRedo (true); } -bool SingleLineTextEditor::redo() { return undoOrRedo (false); } - -//============================================================================== -bool SingleLineTextEditor::isReadOnly() const noexcept -{ - return readOnly || ! isEnabled(); -} - -bool SingleLineTextEditor::isTextInputActive() const -{ - return ! isReadOnly(); -} - -void SingleLineTextEditor::setTabKeyUsedAsCharacter (const bool shouldTabKeyBeUsed) -{ - tabKeyUsed = shouldTabKeyBeUsed; -} - -void SingleLineTextEditor::setPopupMenuEnabled (const bool b) -{ - popupMenuEnabled = b; -} - -void SingleLineTextEditor::setSelectAllWhenFocused (const bool b) -{ - selectAllTextWhenFocused = b; -} - -//============================================================================== -void SingleLineTextEditor::setFont (const Font& newFont) -{ - currentFont = newFont; -} - -void SingleLineTextEditor::applyFontToAllText (const Font& newFont) -{ - currentFont = newFont; - const Colour overallColour (findColour (textColourId)); - - for (int i = sections.size(); --i >= 0;) - { - UniformTextSection* const uts = sections.getUnchecked (i); - uts->setFont (newFont); - uts->colour = overallColour; - } - - coalesceSimilarSections(); - repaint(); -} - -void SingleLineTextEditor::colourChanged() -{ - setOpaque (findColour (backgroundColourId).isOpaque()); - repaint(); -} - -void SingleLineTextEditor::lookAndFeelChanged() -{ - caret = nullptr; - recreateCaret(); - repaint(); -} - -void SingleLineTextEditor::enablementChanged() -{ - recreateCaret(); - repaint(); -} - -void SingleLineTextEditor::setCaretVisible (const bool shouldCaretBeVisible) -{ - if (caretVisible != shouldCaretBeVisible) - { - caretVisible = shouldCaretBeVisible; - recreateCaret(); - } -} - -void SingleLineTextEditor::recreateCaret() -{ - if (isCaretVisible()) - { - if (caret == nullptr) - { - caret.reset (getLookAndFeel().createCaretComponent (this)); - textHolder->addChildComponent (*caret); - updateCaretPosition(); - } - } - else - { - caret = nullptr; - } -} - -void SingleLineTextEditor::updateCaretPosition() -{ - if (caret != nullptr) - caret->setCaretPosition (getCaretRectangle()); -} - -SingleLineTextEditor::LengthAndCharacterRestriction::LengthAndCharacterRestriction (int maxLen, const String& chars) - : allowedCharacters (chars), maxLength (maxLen) -{} - -String SingleLineTextEditor::LengthAndCharacterRestriction::filterNewText (SingleLineTextEditor& ed, const String& newInput) -{ - String t (newInput); - - if (allowedCharacters.isNotEmpty()) - t = t.retainCharacters (allowedCharacters); - - if (maxLength > 0) - t = t.substring (0, maxLength - (ed.getTotalNumChars() - ed.getHighlightedRegion().getLength())); - - return t; -} - -void SingleLineTextEditor::setInputFilter (InputFilter* newFilter, bool takeOwnership) -{ - inputFilter.set (newFilter, takeOwnership); -} - -void SingleLineTextEditor::setInputRestrictions (const int maxLen, const String& chars) -{ - setInputFilter (new LengthAndCharacterRestriction (maxLen, chars), true); -} - -void SingleLineTextEditor::setTextToShowWhenEmpty (const String& text, Colour colourToUse) -{ - textToShowWhenEmpty = text; - colourForTextWhenEmpty = colourToUse; -} - -//============================================================================== -void SingleLineTextEditor::clear() -{ - clearInternal (nullptr); - undoManager.clearUndoHistory(); -} - -void SingleLineTextEditor::setText (const String& newText, - const bool sendTextChangeMessage) -{ - const int newLength = newText.length(); - - if (newLength != getTotalNumChars() || getText() != newText) - { - textValue = newText; - - int oldCursorPos = caretPosition; - const bool cursorWasAtEnd = oldCursorPos >= getTotalNumChars(); - - clearInternal (nullptr); - insert (newText, 0, currentFont, findColour (textColourId), nullptr, caretPosition); - - if (cursorWasAtEnd) - oldCursorPos = getTotalNumChars(); - - moveCaretTo (oldCursorPos, false); - - if (sendTextChangeMessage) - textChanged(); - - undoManager.clearUndoHistory(); - - repaint(); - } -} - -//============================================================================== -void SingleLineTextEditor::updateValueFromText() -{ - if (valueTextNeedsUpdating) - { - valueTextNeedsUpdating = false; - textValue = getText(); - } -} - -Value& SingleLineTextEditor::getTextValue() -{ - updateValueFromText(); - return textValue; -} - -void SingleLineTextEditor::textWasChangedByValue() -{ - if (textValue.getValueSource().getReferenceCount() > 1) - setText (textValue.getValue()); -} - -//============================================================================== -void SingleLineTextEditor::textChanged() -{ - if (listeners.size() > 0) - postCommandMessage (TextEditorDefs::textChangeMessageId); - - if (textValue.getValueSource().getReferenceCount() > 1) - { - valueTextNeedsUpdating = false; - textValue = getText(); - } -} - -void SingleLineTextEditor::returnPressed() { postCommandMessage (TextEditorDefs::returnKeyMessageId); } -void SingleLineTextEditor::escapePressed() { postCommandMessage (TextEditorDefs::escapeKeyMessageId); } - -void SingleLineTextEditor::addListener (SingleLineTextEditor::Listener* const l) { listeners.add (l); } -void SingleLineTextEditor::removeListener (SingleLineTextEditor::Listener* const l) { listeners.remove (l); } - -//============================================================================== -void SingleLineTextEditor::timerCallbackInt() -{ - if (hasKeyboardFocus (false) && ! isCurrentlyBlockedByAnotherModalComponent()) - wasFocused = true; - - const unsigned int now = Time::getApproximateMillisecondCounter(); - - if (now > lastTransactionTime + 200) - newTransaction(); -} - -void SingleLineTextEditor::repaintText (const Range range) -{ - if (! range.isEmpty()) - { - float x = 0, y = 0, lh = currentFont.getHeight(); - - const float wordWrapWidth = getWordWrapWidth(); - - if (wordWrapWidth > 0) - { - Iterator i (sections, wordWrapWidth, justification); - - i.getCharPosition (range.getStart(), x, y, lh); - - const int y1 = (int) y; - int y2; - - if (range.getEnd() >= getTotalNumChars()) - { - y2 = textHolder->getHeight(); - } - else - { - i.getCharPosition (range.getEnd(), x, y, lh); - y2 = (int) (y + lh * 2.0f); - } - - textHolder->repaint (0, y1, textHolder->getWidth(), y2 - y1); - } - } -} - -//============================================================================== -void SingleLineTextEditor::moveCaret (int newCaretPos) -{ - if (newCaretPos < 0) - newCaretPos = 0; - else - newCaretPos = jmin (newCaretPos, getTotalNumChars()); - - if (newCaretPos != getCaretPosition()) - { - caretPosition = newCaretPos; - textHolder->restartTimer(); - updateCaretPosition(); - } -} - -int SingleLineTextEditor::getCaretPosition() const -{ - return caretPosition; -} - -void SingleLineTextEditor::setCaretPosition (const int newIndex) -{ - moveCaretTo (newIndex, false); -} - -void SingleLineTextEditor::moveCaretToEnd() -{ - moveCaretTo (std::numeric_limits::max(), false); -} - -Rectangle SingleLineTextEditor::getCaretRectangle() -{ - float cursorX, cursorY; - float cursorHeight = currentFont.getHeight(); // (in case the text is empty and the call below doesn't set this value) - getCharPosition (caretPosition, cursorX, cursorY, cursorHeight); - - return Rectangle (roundToInt (cursorX), roundToInt (cursorY), 2, roundToInt (cursorHeight)); -} - -//============================================================================== -enum { rightEdgeSpace = 2 }; - -float SingleLineTextEditor::getWordWrapWidth() const -{ - return std::numeric_limits::max(); -} - -int SingleLineTextEditor::getTextWidth() const { return textHolder->getWidth(); } -int SingleLineTextEditor::getTextHeight() const { return textHolder->getHeight(); } - -void SingleLineTextEditor::moveCaretTo (const int newPosition, const bool isSelecting) -{ - if (isSelecting) - { - moveCaret (newPosition); - - const Range oldSelection (selection); - - if (dragType == notDragging) - { - if (abs (getCaretPosition() - selection.getStart()) < abs (getCaretPosition() - selection.getEnd())) - dragType = draggingSelectionStart; - else - dragType = draggingSelectionEnd; - } - - if (dragType == draggingSelectionStart) - { - if (getCaretPosition() >= selection.getEnd()) - dragType = draggingSelectionEnd; - - selection = Range::between (getCaretPosition(), selection.getEnd()); - } - else - { - if (getCaretPosition() < selection.getStart()) - dragType = draggingSelectionStart; - - selection = Range::between (getCaretPosition(), selection.getStart()); - } - - repaintText (selection.getUnionWith (oldSelection)); - } - else - { - dragType = notDragging; - - repaintText (selection); - - moveCaret (newPosition); - selection = Range::emptyRange (getCaretPosition()); - } -} - -int SingleLineTextEditor::getTextIndexAt (const int x, const int y) -{ - return indexAtPosition ((float) x, (float) y); -} - -void SingleLineTextEditor::insertTextAtCaret (const String& t) -{ - String newText (inputFilter != nullptr ? inputFilter->filterNewText (*this, t) : t); - - newText = newText.replaceCharacters ("\r\n", " "); - - const int insertIndex = selection.getStart(); - const int newCaretPos = insertIndex + newText.length(); - - remove (selection, getUndoManager(), - newText.isNotEmpty() ? newCaretPos - 1 : newCaretPos); - - insert (newText, insertIndex, currentFont, findColour (textColourId), - getUndoManager(), newCaretPos); - - textChanged(); -} - -void SingleLineTextEditor::setHighlightedRegion (const Range& newSelection) -{ - moveCaretTo (newSelection.getStart(), false); - moveCaretTo (newSelection.getEnd(), true); -} - -//============================================================================== -void SingleLineTextEditor::copy() -{ - const String selectedText (getHighlightedText()); - - if (selectedText.isNotEmpty()) - SystemClipboard::copyTextToClipboard (selectedText); -} - -void SingleLineTextEditor::paste() -{ - if (! isReadOnly()) - { - const String clip (SystemClipboard::getTextFromClipboard()); - - if (clip.isNotEmpty()) - insertTextAtCaret (clip); - } -} - -void SingleLineTextEditor::cut() -{ - if (! isReadOnly()) - { - moveCaret (selection.getEnd()); - insertTextAtCaret (String()); - } -} - -//============================================================================== -void SingleLineTextEditor::drawContent (Graphics& g) -{ - Rectangle r = getLocalBounds(); - - GlyphArrangement ga; - ga.addFittedText (getFont(), getText(), - float (r.getX()), float (r.getY()), - float (r.getWidth()), float (r.getHeight()), justification, 1); - - Colour selectedTextColour = findColour (highlightedTextColourId); - Colour normalTextColour = findColour (textColourId); - - if (! selection.isEmpty()) - { - g.setColour (findColour (highlightColourId).withMultipliedAlpha (hasKeyboardFocus (true) ? 1.0f : 0.5f)); - - auto s = selection.getStart(); - auto e = selection.getEnd(); - - float x1, y1, x2, y2, h1, h2; - getCharPosition (s, x1, y1, h1); - getCharPosition (e, x2, y2, h2); - - if (x2 - x1 > 0) - g.fillRect (x1, y1, x2 - x1, h1); - } - - for (int i = 0; i < ga.getNumGlyphs(); i++) - { - if (selection.contains (i)) - g.setColour (selectedTextColour); - else - g.setColour (normalTextColour); - - ga.getGlyph (i).draw (g); - } -} - -void SingleLineTextEditor::paint (Graphics& g) -{ - if (LookAndFeelMethods* lfm = dynamic_cast (&getLookAndFeel())) - lfm->fillSingleLineTextEditorBackground (g, getWidth(), getHeight(), *this); -} - -void SingleLineTextEditor::paintOverChildren (Graphics& g) -{ - if (textToShowWhenEmpty.isNotEmpty() - && (! hasKeyboardFocus (false)) - && getTotalNumChars() == 0) - { - g.setColour (colourForTextWhenEmpty); - g.setFont (getFont()); - - g.drawText (textToShowWhenEmpty, - 0, 0, getWidth(), getHeight(), - justification, true); - } - - if (LookAndFeelMethods* lfm = dynamic_cast (&getLookAndFeel())) - lfm->drawSingleLineTextEditorOutline (g, getWidth(), getHeight(), *this); -} - -//============================================================================== -void SingleLineTextEditor::addPopupMenuItems (PopupMenu& m, const MouseEvent*) -{ - const bool writable = ! isReadOnly(); - - m.addItem (StandardApplicationCommandIDs::cut, TRANS("Cut"), writable); - m.addItem (StandardApplicationCommandIDs::copy, TRANS("Copy"), ! selection.isEmpty()); - m.addItem (StandardApplicationCommandIDs::paste, TRANS("Paste"), writable); - m.addItem (StandardApplicationCommandIDs::del, TRANS("Delete"), writable); - m.addSeparator(); - m.addItem (StandardApplicationCommandIDs::selectAll, TRANS("Select All")); - m.addSeparator(); - - if (getUndoManager() != nullptr) - { - m.addItem (StandardApplicationCommandIDs::undo, TRANS("Undo"), undoManager.canUndo()); - m.addItem (StandardApplicationCommandIDs::redo, TRANS("Redo"), undoManager.canRedo()); - } -} - -void SingleLineTextEditor::performPopupMenuAction (const int menuItemID) -{ - switch (menuItemID) - { - case StandardApplicationCommandIDs::cut: cutToClipboard(); break; - case StandardApplicationCommandIDs::copy: copyToClipboard(); break; - case StandardApplicationCommandIDs::paste: pasteFromClipboard(); break; - case StandardApplicationCommandIDs::del: cut(); break; - case StandardApplicationCommandIDs::selectAll: selectAll(); break; - case StandardApplicationCommandIDs::undo: undo(); break; - case StandardApplicationCommandIDs::redo: redo(); break; - default: break; - } -} - -static void textEditorMenuCallback (int menuResult, SingleLineTextEditor* editor) -{ - if (editor != nullptr && menuResult != 0) - editor->performPopupMenuAction (menuResult); -} - -//============================================================================== -void SingleLineTextEditor::mouseDown (const MouseEvent& e) -{ - beginDragAutoRepeat (100); - newTransaction(); - - if (wasFocused || ! selectAllTextWhenFocused) - { - if (! (popupMenuEnabled && e.mods.isPopupMenu())) - { - moveCaretTo (getTextIndexAt (e.x, e.y), - e.mods.isShiftDown()); - } - else - { - PopupMenu m; - m.setLookAndFeel (&getLookAndFeel()); - addPopupMenuItems (m, &e); - - m.showMenuAsync (PopupMenu::Options(), - ModalCallbackFunction::forComponent (textEditorMenuCallback, this)); - } - } -} - -void SingleLineTextEditor::mouseDrag (const MouseEvent& e) -{ - if (wasFocused || ! selectAllTextWhenFocused) - if (! (popupMenuEnabled && e.mods.isPopupMenu())) - moveCaretTo (getTextIndexAt (e.x, e.y), true); -} - -void SingleLineTextEditor::mouseUp (const MouseEvent& e) -{ - newTransaction(); - textHolder->restartTimer(); - - if (wasFocused || ! selectAllTextWhenFocused) - if (e.mouseWasClicked() && ! (popupMenuEnabled && e.mods.isPopupMenu())) - moveCaret (getTextIndexAt (e.x, e.y)); - - wasFocused = true; -} - -void SingleLineTextEditor::mouseDoubleClick (const MouseEvent& e) -{ - int tokenEnd = getTextIndexAt (e.x, e.y); - int tokenStart = 0; - - if (e.getNumberOfClicks() > 3) - { - tokenEnd = getTotalNumChars(); - } - else - { - const String t (getText()); - const int totalLength = getTotalNumChars(); - - while (tokenEnd < totalLength) - { - // (note the slight bodge here - it's because iswalnum only checks for alphabetic chars in the current locale) - const juce_wchar c = t [tokenEnd]; - if (CharacterFunctions::isLetterOrDigit (c) || c > 128) - ++tokenEnd; - else - break; - } - - tokenStart = tokenEnd; - - while (tokenStart > 0) - { - // (note the slight bodge here - it's because iswalnum only checks for alphabetic chars in the current locale) - const juce_wchar c = t [tokenStart - 1]; - if (CharacterFunctions::isLetterOrDigit (c) || c > 128) - --tokenStart; - else - break; - } - - if (e.getNumberOfClicks() > 2) - { - while (tokenEnd < totalLength) - { - const juce_wchar c = t [tokenEnd]; - if (c != '\r' && c != '\n') - ++tokenEnd; - else - break; - } - - while (tokenStart > 0) - { - const juce_wchar c = t [tokenStart - 1]; - if (c != '\r' && c != '\n') - --tokenStart; - else - break; - } - } - } - - moveCaretTo (tokenEnd, false); - moveCaretTo (tokenStart, true); -} - -void SingleLineTextEditor::mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wheel) -{ - Component::mouseWheelMove (e, wheel); -} - -//============================================================================== -bool SingleLineTextEditor::moveCaretWithTransaction (const int newPos, const bool selecting) -{ - newTransaction(); - moveCaretTo (newPos, selecting); - return true; -} - -bool SingleLineTextEditor::moveCaretLeft (bool moveInWholeWordSteps, bool selecting) -{ - int pos = getCaretPosition(); - - if (moveInWholeWordSteps) - pos = findWordBreakBefore (pos); - else - --pos; - - return moveCaretWithTransaction (pos, selecting); -} - -bool SingleLineTextEditor::moveCaretRight (bool moveInWholeWordSteps, bool selecting) -{ - int pos = getCaretPosition(); - - if (moveInWholeWordSteps) - pos = findWordBreakAfter (pos); - else - ++pos; - - return moveCaretWithTransaction (pos, selecting); -} - -bool SingleLineTextEditor::moveCaretUp (bool selecting) -{ - return moveCaretToStartOfLine (selecting); -} - -bool SingleLineTextEditor::moveCaretDown (bool selecting) -{ - return moveCaretToEndOfLine (selecting); -} - -bool SingleLineTextEditor::pageUp (bool selecting) -{ - return moveCaretToStartOfLine (selecting); -} - -bool SingleLineTextEditor::pageDown (bool selecting) -{ - return moveCaretToEndOfLine (selecting); -} - -bool SingleLineTextEditor::moveCaretToTop (bool selecting) -{ - return moveCaretWithTransaction (0, selecting); -} - -bool SingleLineTextEditor::moveCaretToStartOfLine (bool selecting) -{ - const Rectangle caretPos (getCaretRectangle().toFloat()); - return moveCaretWithTransaction (indexAtPosition (0.0f, caretPos.getY()), selecting); -} - -bool SingleLineTextEditor::moveCaretToEnd (bool selecting) -{ - return moveCaretWithTransaction (getTotalNumChars(), selecting); -} - -bool SingleLineTextEditor::moveCaretToEndOfLine (bool selecting) -{ - const Rectangle caretPos (getCaretRectangle().toFloat()); - return moveCaretWithTransaction (indexAtPosition ((float) textHolder->getWidth(), caretPos.getY()), selecting); -} - -bool SingleLineTextEditor::deleteBackwards (bool moveInWholeWordSteps) -{ - if (moveInWholeWordSteps) - moveCaretTo (findWordBreakBefore (getCaretPosition()), true); - else if (selection.isEmpty() && selection.getStart() > 0) - selection = Range (selection.getEnd() - 1, selection.getEnd()); - - cut(); - return true; -} - -bool SingleLineTextEditor::deleteForwards (bool /*moveInWholeWordSteps*/) -{ - if (selection.isEmpty() && selection.getStart() < getTotalNumChars()) - selection = Range (selection.getStart(), selection.getStart() + 1); - - cut(); - return true; -} - -bool SingleLineTextEditor::copyToClipboard() -{ - newTransaction(); - copy(); - return true; -} - -bool SingleLineTextEditor::cutToClipboard() -{ - newTransaction(); - copy(); - cut(); - return true; -} - -bool SingleLineTextEditor::pasteFromClipboard() -{ - newTransaction(); - paste(); - return true; -} - -bool SingleLineTextEditor::selectAll() -{ - newTransaction(); - moveCaretTo (0, false); - moveCaretTo (getTotalNumChars(), true); - return true; -} - -//============================================================================== -void SingleLineTextEditor::setEscapeAndReturnKeysConsumed (bool shouldBeConsumed) noexcept -{ - consumeEscAndReturnKeys = shouldBeConsumed; -} - -bool SingleLineTextEditor::keyPressed (const KeyPress& key) -{ - if (isReadOnly() && key != KeyPress ('c', ModifierKeys::commandModifier, 0)) - return false; - - if (! TextEditorKeyMapper::invokeKeyFunction (*this, key)) - { - if (key == KeyPress::returnKey) - { - newTransaction(); - - returnPressed(); - return consumeEscAndReturnKeys; - } - else if (key.isKeyCode (KeyPress::escapeKey)) - { - newTransaction(); - moveCaretTo (getCaretPosition(), false); - escapePressed(); - return consumeEscAndReturnKeys; - } - else if (key.getTextCharacter() >= ' ' - || (tabKeyUsed && (key.getTextCharacter() == '\t'))) - { - insertTextAtCaret (String::charToString (key.getTextCharacter())); - - lastTransactionTime = Time::getApproximateMillisecondCounter(); - } - else - { - return false; - } - } - - return true; -} - -bool SingleLineTextEditor::keyStateChanged (const bool isKeyDown) -{ - if (! isKeyDown) - return false; - - #if JUCE_WINDOWS - if (KeyPress (KeyPress::F4Key, ModifierKeys::altModifier, 0).isCurrentlyDown()) - return false; // We need to explicitly allow alt-F4 to pass through on Windows - #endif - - if ((! consumeEscAndReturnKeys) - && (KeyPress (KeyPress::escapeKey).isCurrentlyDown() - || KeyPress (KeyPress::returnKey).isCurrentlyDown())) - return false; - - // (overridden to avoid forwarding key events to the parent) - return ! ModifierKeys::getCurrentModifiers().isCommandDown(); -} - -//============================================================================== -void SingleLineTextEditor::focusGained (FocusChangeType) -{ - newTransaction(); - - if (selectAllTextWhenFocused) - { - moveCaretTo (0, false); - moveCaretTo (getTotalNumChars(), true); - } - - repaint(); - updateCaretPosition(); - - if (ComponentPeer* const peer = getPeer()) - if (! isReadOnly()) - peer->textInputRequired (peer->globalToLocal (getScreenPosition()), *this); -} - -void SingleLineTextEditor::focusLost (FocusChangeType) -{ - newTransaction(); - - wasFocused = false; - textHolder->stopTimer(); - - underlinedSections.clear(); - - if (ComponentPeer* const peer = getPeer()) - peer->dismissPendingTextInput(); - - updateCaretPosition(); - - postCommandMessage (TextEditorDefs::focusLossMessageId); - repaint(); -} - -//============================================================================== -void SingleLineTextEditor::resized() -{ - textHolder->setBounds (getLocalBounds()); - updateCaretPosition(); -} - -void SingleLineTextEditor::handleCommandMessage (const int commandId) -{ - Component::BailOutChecker checker (this); - - switch (commandId) - { - case TextEditorDefs::textChangeMessageId: - listeners.callChecked (checker, &SingleLineTextEditor::Listener::sltextEditorTextChanged, (SingleLineTextEditor&) *this); - break; - - case TextEditorDefs::returnKeyMessageId: - listeners.callChecked (checker, &SingleLineTextEditor::Listener::sltextEditorReturnKeyPressed, (SingleLineTextEditor&) *this); - break; - - case TextEditorDefs::escapeKeyMessageId: - listeners.callChecked (checker, &SingleLineTextEditor::Listener::sltextEditorEscapeKeyPressed, (SingleLineTextEditor&) *this); - break; - - case TextEditorDefs::focusLossMessageId: - updateValueFromText(); - listeners.callChecked (checker, &SingleLineTextEditor::Listener::sltextEditorFocusLost, (SingleLineTextEditor&) *this); - break; - - default: - jassertfalse; - break; - } -} - -void SingleLineTextEditor::setTemporaryUnderlining (const Array >& newUnderlinedSections) -{ - underlinedSections = newUnderlinedSections; - repaint(); -} - -//============================================================================== -UndoManager* SingleLineTextEditor::getUndoManager() noexcept -{ - return readOnly ? nullptr : &undoManager; -} - -void SingleLineTextEditor::clearInternal (UndoManager* const um) -{ - remove (Range (0, getTotalNumChars()), um, caretPosition); -} - -void SingleLineTextEditor::insert (const String& text, - const int insertIndex, - const Font& font, - const Colour colour, - UndoManager* const um, - const int caretPositionToMoveTo) -{ - if (text.isNotEmpty()) - { - if (um != nullptr) - { - if (um->getNumActionsInCurrentTransaction() > TextEditorDefs::maxActionsPerTransaction) - newTransaction(); - - um->perform (new InsertAction (*this, text, insertIndex, font, colour, - caretPosition, caretPositionToMoveTo)); - } - else - { - repaintText (Range (insertIndex, getTotalNumChars())); // must do this before and after changing the data, in case - // a line gets moved due to word wrap - - int index = 0; - int nextIndex = 0; - - for (int i = 0; i < sections.size(); ++i) - { - nextIndex = index + sections.getUnchecked (i)->getTotalLength(); - - if (insertIndex == index) - { - sections.insert (i, new UniformTextSection (text, font, colour)); - break; - } - else if (insertIndex > index && insertIndex < nextIndex) - { - splitSection (i, insertIndex - index); - sections.insert (i + 1, new UniformTextSection (text, font, colour)); - break; - } - - index = nextIndex; - } - - if (nextIndex == insertIndex) - sections.add (new UniformTextSection (text, font, colour)); - - coalesceSimilarSections(); - totalNumChars = -1; - valueTextNeedsUpdating = true; - - moveCaretTo (caretPositionToMoveTo, false); - - repaintText (Range (insertIndex, getTotalNumChars())); - } - } -} - -void SingleLineTextEditor::reinsert (const int insertIndex, const OwnedArray& sectionsToInsert) -{ - int index = 0; - int nextIndex = 0; - - for (int i = 0; i < sections.size(); ++i) - { - nextIndex = index + sections.getUnchecked (i)->getTotalLength(); - - if (insertIndex == index) - { - for (int j = sectionsToInsert.size(); --j >= 0;) - sections.insert (i, new UniformTextSection (*sectionsToInsert.getUnchecked(j))); - - break; - } - else if (insertIndex > index && insertIndex < nextIndex) - { - splitSection (i, insertIndex - index); - - for (int j = sectionsToInsert.size(); --j >= 0;) - sections.insert (i + 1, new UniformTextSection (*sectionsToInsert.getUnchecked(j))); - - break; - } - - index = nextIndex; - } - - if (nextIndex == insertIndex) - { - for (int j = 0; j < sectionsToInsert.size(); ++j) - sections.add (new UniformTextSection (*sectionsToInsert.getUnchecked(j))); - } - - coalesceSimilarSections(); - totalNumChars = -1; - valueTextNeedsUpdating = true; -} - -void SingleLineTextEditor::remove (Range range, UndoManager* const um, const int caretPositionToMoveTo) -{ - if (! range.isEmpty()) - { - int index = 0; - - for (int i = 0; i < sections.size(); ++i) - { - const int nextIndex = index + sections.getUnchecked(i)->getTotalLength(); - - if (range.getStart() > index && range.getStart() < nextIndex) - { - splitSection (i, range.getStart() - index); - --i; - } - else if (range.getEnd() > index && range.getEnd() < nextIndex) - { - splitSection (i, range.getEnd() - index); - --i; - } - else - { - index = nextIndex; - - if (index > range.getEnd()) - break; - } - } - - index = 0; - - if (um != nullptr) - { - Array removedSections; - - for (int i = 0; i < sections.size(); ++i) - { - if (range.getEnd() <= range.getStart()) - break; - - UniformTextSection* const section = sections.getUnchecked (i); - - const int nextIndex = index + section->getTotalLength(); - - if (range.getStart() <= index && range.getEnd() >= nextIndex) - removedSections.add (new UniformTextSection (*section)); - - index = nextIndex; - } - - if (um->getNumActionsInCurrentTransaction() > TextEditorDefs::maxActionsPerTransaction) - newTransaction(); - - um->perform (new RemoveAction (*this, range, caretPosition, - caretPositionToMoveTo, removedSections)); - } - else - { - Range remainingRange (range); - - for (int i = 0; i < sections.size(); ++i) - { - UniformTextSection* const section = sections.getUnchecked (i); - - const int nextIndex = index + section->getTotalLength(); - - if (remainingRange.getStart() <= index && remainingRange.getEnd() >= nextIndex) - { - sections.remove (i); - - remainingRange.setEnd (remainingRange.getEnd() - (nextIndex - index)); - if (remainingRange.isEmpty()) - break; - - --i; - } - else - { - index = nextIndex; - } - } - - coalesceSimilarSections(); - totalNumChars = -1; - valueTextNeedsUpdating = true; - - moveCaretTo (caretPositionToMoveTo, false); - - repaintText (Range (range.getStart(), getTotalNumChars())); - } - } -} - -//============================================================================== -String SingleLineTextEditor::getText() const -{ - MemoryOutputStream mo; - mo.preallocate ((size_t) getTotalNumChars()); - - for (int i = 0; i < sections.size(); ++i) - sections.getUnchecked (i)->appendAllText (mo); - - return mo.toUTF8(); -} - -String SingleLineTextEditor::getTextInRange (const Range& range) const -{ - if (range.isEmpty()) - return String(); - - MemoryOutputStream mo; - mo.preallocate ((size_t) jmin (getTotalNumChars(), range.getLength())); - - int index = 0; - - for (int i = 0; i < sections.size(); ++i) - { - const UniformTextSection* const s = sections.getUnchecked (i); - const int nextIndex = index + s->getTotalLength(); - - if (range.getStart() < nextIndex) - { - if (range.getEnd() <= index) - break; - - s->appendSubstring (mo, range - index); - } - - index = nextIndex; - } - - return mo.toUTF8(); -} - -String SingleLineTextEditor::getHighlightedText() const -{ - return getTextInRange (selection); -} - -int SingleLineTextEditor::getTotalNumChars() const -{ - if (totalNumChars < 0) - { - totalNumChars = 0; - - for (int i = sections.size(); --i >= 0;) - totalNumChars += sections.getUnchecked (i)->getTotalLength(); - } - - return totalNumChars; -} - -bool SingleLineTextEditor::isEmpty() const -{ - return getTotalNumChars() == 0; -} - -void SingleLineTextEditor::getCharPosition (const int index, float& cx, float& cy, float& lineHeight) const -{ - Rectangle r = getLocalBounds(); - - GlyphArrangement ga; - ga.addFittedText (getFont(), getText(), - float (r.getX()), float (r.getY()), - float (r.getWidth()), float (r.getHeight()), justification, 1); - - const int numGlyphs = ga.getNumGlyphs(); - if (numGlyphs == 0) - { - cx = float (r.getCentreX()); - cy = 1; - } - else if (index >= 0 && index < numGlyphs) - { - PositionedGlyph& pg = ga.getGlyph (index); - - cx = pg.getLeft(); - cy = pg.getTop(); - lineHeight = pg.getBottom() - pg.getTop(); - } - else if (numGlyphs > 0 && numGlyphs == index) - { - PositionedGlyph& pg = ga.getGlyph (index - 1); - - cx = pg.getRight(); - cy = pg.getTop(); - lineHeight = pg.getBottom() - pg.getTop(); - } - else - { - cx = 0; - cy = 0; - lineHeight = 0; - } -} - -int SingleLineTextEditor::indexAtPosition (const float x, const float) -{ - Rectangle r = getLocalBounds(); - - GlyphArrangement ga; - ga.addFittedText (getFont(), getText(), - float (r.getX()), float (r.getY()), - float (r.getWidth()), float (r.getHeight()), justification, 1); - - const int numGlyphs = ga.getNumGlyphs(); - - if (numGlyphs > 0) - { - PositionedGlyph& pg = ga.getGlyph (numGlyphs - 1); - if (x >= pg.getRight()) - return numGlyphs; - } - - for (int i = numGlyphs; --i >= 0;) - { - PositionedGlyph& pg = ga.getGlyph (i); - - if (x >= pg.getLeft()) - return i; - } - return getTotalNumChars(); -} - -//============================================================================== -int SingleLineTextEditor::findWordBreakAfter (const int position) const -{ - const String t (getTextInRange (Range (position, position + 512))); - const int totalLength = t.length(); - int i = 0; - - while (i < totalLength && CharacterFunctions::isWhitespace (t[i])) - ++i; - - const int type = TextEditorDefs::getCharacterCategory (t[i]); - - while (i < totalLength && type == TextEditorDefs::getCharacterCategory (t[i])) - ++i; - - while (i < totalLength && CharacterFunctions::isWhitespace (t[i])) - ++i; - - return position + i; -} - -int SingleLineTextEditor::findWordBreakBefore (const int position) const -{ - if (position <= 0) - return 0; - - const int startOfBuffer = jmax (0, position - 512); - const String t (getTextInRange (Range (startOfBuffer, position))); - - int i = position - startOfBuffer; - - while (i > 0 && CharacterFunctions::isWhitespace (t [i - 1])) - --i; - - if (i > 0) - { - const int type = TextEditorDefs::getCharacterCategory (t [i - 1]); - - while (i > 0 && type == TextEditorDefs::getCharacterCategory (t [i - 1])) - --i; - } - - jassert (startOfBuffer + i >= 0); - return startOfBuffer + i; -} - - -//============================================================================== -void SingleLineTextEditor::splitSection (const int sectionIndex, const int charToSplitAt) -{ - jassert (sections[sectionIndex] != nullptr); - - sections.insert (sectionIndex + 1, - sections.getUnchecked (sectionIndex)->split (charToSplitAt)); -} - -void SingleLineTextEditor::coalesceSimilarSections() -{ - for (int i = 0; i < sections.size() - 1; ++i) - { - UniformTextSection* const s1 = sections.getUnchecked (i); - UniformTextSection* const s2 = sections.getUnchecked (i + 1); - - if (s1->font == s2->font - && s1->colour == s2->colour) - { - s1->append (*s2); - sections.remove (i + 1); - --i; - } - } -} diff --git a/Modules/gin/components/singlelinetexteditor.h b/Modules/gin/components/singlelinetexteditor.h deleted file mode 100755 index 8e77dd0..0000000 --- a/Modules/gin/components/singlelinetexteditor.h +++ /dev/null @@ -1,617 +0,0 @@ -/* - ============================================================================== - - This file is part of the JUCE library. - Copyright (c) 2015 - ROLI Ltd. - - Permission is granted to use this software under the terms of either: - a) the GPL v2 (or any later version) - b) the Affero GPL v3 - - Details of these licenses can be found at: www.gnu.org/licenses - - JUCE is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - ------------------------------------------------------------------------------ - - To release a closed-source product which uses JUCE, commercial licenses are - available: visit www.juce.com for more information. - - ============================================================================== -*/ - -#pragma once - -//============================================================================== -/** - An editable text box. - - A TextEditor can either be in single- or multi-line mode, and supports mixed - fonts and colours. - - @see TextEditor::Listener, Label -*/ -class SingleLineTextEditor : public Component, - public TextInputTarget, - public SettableTooltipClient -{ -public: - //============================================================================== - /** Creates a new, empty text editor. - - @param componentName the name to pass to the component for it to use as its name - */ - explicit SingleLineTextEditor (const String& componentName = String()); - - /** Destructor. */ - ~SingleLineTextEditor() override; - - /** Indicates whether the tab key should be accepted and used to input a tab character, - or whether it gets ignored. - - By default the tab key is ignored, so that it can be used to switch keyboard focus - between components. - */ - void setTabKeyUsedAsCharacter (bool shouldTabKeyBeUsed); - - /** Returns true if the tab key is being used for input. - @see setTabKeyUsedAsCharacter - */ - bool isTabKeyUsedAsCharacter() const { return tabKeyUsed; } - - /** This can be used to change whether escape and return keypress events are - propagated up to the parent component. - The default here is true, meaning that these events are not allowed to reach the - parent, but you may want to allow them through so that they can trigger other - actions, e.g. closing a dialog box, etc. - */ - void setEscapeAndReturnKeysConsumed (bool shouldBeConsumed) noexcept; - - //============================================================================== - /** Changes the editor to read-only mode. - - By default, the text editor is not read-only. If you're making it read-only, you - might also want to call setCaretVisible (false) to get rid of the caret. - - The text can still be highlighted and copied when in read-only mode. - - @see isReadOnly, setCaretVisible - */ - void setReadOnly (bool shouldBeReadOnly); - - /** Returns true if the editor is in read-only mode. */ - bool isReadOnly() const noexcept; - - //============================================================================== - /** Makes the caret visible or invisible. - By default the caret is visible. - @see setCaretColour, setCaretPosition - */ - void setCaretVisible (bool shouldBeVisible); - - /** Returns true if the caret is enabled. - @see setCaretVisible - */ - bool isCaretVisible() const noexcept { return caretVisible && ! isReadOnly(); } - - //============================================================================== - /** Allows a right-click menu to appear for the editor. - - (This defaults to being enabled). - - If enabled, right-clicking (or command-clicking on the Mac) will pop up a menu - of options such as cut/copy/paste, undo/redo, etc. - */ - void setPopupMenuEnabled (bool menuEnabled); - - /** Returns true if the right-click menu is enabled. - @see setPopupMenuEnabled - */ - bool isPopupMenuEnabled() const noexcept { return popupMenuEnabled; } - - /** Returns true if a popup-menu is currently being displayed. */ - bool isPopupMenuCurrentlyActive() const noexcept { return menuActive; } - - //============================================================================== - /** A set of colour IDs to use to change the colour of various aspects of the editor. - - These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() - methods. - - NB: You can also set the caret colour using CaretComponent::caretColourId - - @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour - */ - enum ColourIds - { - backgroundColourId = 0x1000200, /**< The colour to use for the text component's background - this can be - transparent if necessary. */ - - textColourId = 0x1000201, /**< The colour that will be used when text is added to the editor. Note - that because the editor can contain multiple colours, calling this - method won't change the colour of existing text - to do that, call - applyFontToAllText() after calling this method.*/ - - highlightColourId = 0x1000202, /**< The colour with which to fill the background of highlighted sections of - the text - this can be transparent if you don't want to show any - highlighting.*/ - - highlightedTextColourId = 0x1000203, /**< The colour with which to draw the text in highlighted sections. */ - - outlineColourId = 0x1000205, /**< If this is non-transparent, it will be used to draw a box around - the edge of the component. */ - - focusedOutlineColourId = 0x1000206, /**< If this is non-transparent, it will be used to draw a box around - the edge of the component when it has focus. */ - - shadowColourId = 0x1000207, /**< If this is non-transparent, it'll be used to draw an inner shadow - around the edge of the editor. */ - }; - - //============================================================================== - /** Sets the font to use for newly added text. - - This will change the font that will be used next time any text is added or entered - into the editor. It won't change the font of any existing text - to do that, use - applyFontToAllText() instead. - - @see applyFontToAllText - */ - void setFont (const Font& newFont); - - /** Applies a font to all the text in the editor. - This will also set the current font to use for any new text that's added. - @see setFont - */ - void applyFontToAllText (const Font& newFont); - - /** Returns the font that's currently being used for new text. - @see setFont - */ - const Font& getFont() const noexcept { return currentFont; } - - void setJustificationType (Justification just) { justification = just; } - - //============================================================================== - /** If set to true, focusing on the editor will highlight all its text. - - (Set to false by default). - - This is useful for boxes where you expect the user to re-enter all the - text when they focus on the component, rather than editing what's already there. - */ - void setSelectAllWhenFocused (bool shouldSelectAll); - - /** When the text editor is empty, it can be set to display a message. - - This is handy for things like telling the user what to type in the box - the - string is only displayed, it's not taken to actually be the contents of - the editor. - */ - void setTextToShowWhenEmpty (const String& text, Colour colourToUse); - - //============================================================================== - /** - Receives callbacks from a TextEditor component when it changes. - - @see TextEditor::addListener - */ - class JUCE_API Listener - { - public: - /** Destructor. */ - virtual ~Listener() {} - - /** Called when the user changes the text in some way. */ - virtual void sltextEditorTextChanged (SingleLineTextEditor&) {} - - /** Called when the user presses the return key. */ - virtual void sltextEditorReturnKeyPressed (SingleLineTextEditor&) {} - - /** Called when the user presses the escape key. */ - virtual void sltextEditorEscapeKeyPressed (SingleLineTextEditor&) {} - - /** Called when the text editor loses focus. */ - virtual void sltextEditorFocusLost (SingleLineTextEditor&) {} - }; - - //============================================================================== - - /** Registers a listener to be told when things happen to the text. - @see removeListener - */ - void addListener (SingleLineTextEditor::Listener* newListener); - - /** Deregisters a listener. - @see addListener - */ - void removeListener (SingleLineTextEditor::Listener* listenerToRemove); - - //============================================================================== - /** Returns the entire contents of the editor. */ - String getText() const; - - /** Returns a section of the contents of the editor. */ - String getTextInRange (const Range& textRange) const override; - - /** Returns true if there are no characters in the editor. - This is far more efficient than calling getText().isEmpty(). - */ - bool isEmpty() const; - - /** Sets the entire content of the editor. - - This will clear the editor and insert the given text (using the current text colour - and font). You can set the current text colour using - @code setColour (TextEditor::textColourId, ...); - @endcode - - @param newText the text to add - @param sendTextChangeMessage if true, this will cause a change message to - be sent to all the listeners. - @see insertTextAtCaret - */ - void setText (const String& newText, - bool sendTextChangeMessage = true); - - /** Returns a Value object that can be used to get or set the text. - - Bear in mind that this operate quite slowly if your text box contains large - amounts of text, as it needs to dynamically build the string that's involved. - It's best used for small text boxes. - */ - Value& getTextValue(); - - /** Inserts some text at the current caret position. - - If a section of the text is highlighted, it will be replaced by - this string, otherwise it will be inserted. - - To delete a section of text, you can use setHighlightedRegion() to - highlight it, and call insertTextAtCaret (String()). - - @see setCaretPosition, getCaretPosition, setHighlightedRegion - */ - void insertTextAtCaret (const String& textToInsert) override; - - /** Deletes all the text from the editor. */ - void clear(); - - /** Deletes the currently selected region. - This doesn't copy the deleted section to the clipboard - if you need to do that, call copy() first. - @see copy, paste, SystemClipboard - */ - void cut(); - - /** Copies the currently selected region to the clipboard. - @see cut, paste, SystemClipboard - */ - void copy(); - - /** Pastes the contents of the clipboard into the editor at the caret position. - @see cut, copy, SystemClipboard - */ - void paste(); - - //============================================================================== - /** Returns the current index of the caret. - @see setCaretPosition - */ - int getCaretPosition() const; - - /** Moves the caret to be in front of a given character. - @see getCaretPosition, moveCaretToEnd - */ - void setCaretPosition (int newIndex); - - /** Get the graphical position of the caret. - - The rectangle returned is relative to the component's top-left corner. - @see scrollEditorToPositionCaret - */ - Rectangle getCaretRectangle() override; - - /** Selects a section of the text. */ - void setHighlightedRegion (const Range& newSelection) override; - - /** Returns the range of characters that are selected. - If nothing is selected, this will return an empty range. - @see setHighlightedRegion - */ - Range getHighlightedRegion() const override { return selection; } - - /** Returns the section of text that is currently selected. */ - String getHighlightedText() const; - - /** Finds the index of the character at a given position. - The coordinates are relative to the component's top-left. - */ - int getTextIndexAt (int x, int y); - - /** Counts the number of characters in the text. - - This is quicker than getting the text as a string if you just need to know - the length. - */ - int getTotalNumChars() const; - - /** Returns the total width of the text, as it is currently laid-out. - - This may be larger than the size of the TextEditor, and can change when - the TextEditor is resized or the text changes. - */ - int getTextWidth() const; - - /** Returns the maximum height of the text, as it is currently laid-out. - - This may be larger than the size of the TextEditor, and can change when - the TextEditor is resized or the text changes. - */ - int getTextHeight() const; - - //============================================================================== - void moveCaretToEnd(); - bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting); - bool moveCaretRight (bool moveInWholeWordSteps, bool selecting); - bool moveCaretUp (bool selecting); - bool moveCaretDown (bool selecting); - bool pageUp (bool selecting); - bool pageDown (bool selecting); - bool scrollDown() { return false; } - bool scrollUp() { return false; } - bool moveCaretToTop (bool selecting); - bool moveCaretToStartOfLine (bool selecting); - bool moveCaretToEnd (bool selecting); - bool moveCaretToEndOfLine (bool selecting); - bool deleteBackwards (bool moveInWholeWordSteps); - bool deleteForwards (bool moveInWholeWordSteps); - bool copyToClipboard(); - bool cutToClipboard(); - bool pasteFromClipboard(); - bool selectAll(); - bool undo(); - bool redo(); - - //============================================================================== - /** This adds the items to the popup menu. - - By default it adds the cut/copy/paste items, but you can override this if - you need to replace these with your own items. - - If you want to add your own items to the existing ones, you can override this, - call the base class's addPopupMenuItems() method, then append your own items. - - When the menu has been shown, performPopupMenuAction() will be called to - perform the item that the user has chosen. - - The default menu items will be added using item IDs from the - StandardApplicationCommandIDs namespace. - - If this was triggered by a mouse-click, the mouseClickEvent parameter will be - a pointer to the info about it, or may be null if the menu is being triggered - by some other means. - - @see performPopupMenuAction, setPopupMenuEnabled, isPopupMenuEnabled - */ - virtual void addPopupMenuItems (PopupMenu& menuToAddTo, - const MouseEvent* mouseClickEvent); - - /** This is called to perform one of the items that was shown on the popup menu. - - If you've overridden addPopupMenuItems(), you should also override this - to perform the actions that you've added. - - If you've overridden addPopupMenuItems() but have still left the default items - on the menu, remember to call the superclass's performPopupMenuAction() - so that it can perform the default actions if that's what the user clicked on. - - @see addPopupMenuItems, setPopupMenuEnabled, isPopupMenuEnabled - */ - virtual void performPopupMenuAction (int menuItemID); - - //============================================================================== - /** Base class for input filters that can be applied to a TextEditor to restrict - the text that can be entered. - */ - class JUCE_API InputFilter - { - public: - InputFilter() {} - virtual ~InputFilter() {} - - /** This method is called whenever text is entered into the editor. - An implementation of this class should should check the input string, - and return an edited version of it that should be used. - */ - virtual String filterNewText (SingleLineTextEditor&, const String& newInput) = 0; - }; - - /** An input filter for a TextEditor that limits the length of text and/or the - characters that it may contain. - */ - class JUCE_API LengthAndCharacterRestriction : public InputFilter - { - public: - /** Creates a filter that limits the length of text, and/or the characters that it can contain. - @param maxNumChars if this is > 0, it sets a maximum length limit; if <= 0, no - limit is set - @param allowedCharacters if this is non-empty, then only characters that occur in - this string are allowed to be entered into the editor. - */ - LengthAndCharacterRestriction (int maxNumChars, const String& allowedCharacters); - - String filterNewText (SingleLineTextEditor&, const String&) override; - - private: - String allowedCharacters; - int maxLength; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LengthAndCharacterRestriction) - }; - - /** Sets an input filter that should be applied to this editor. - The filter can be nullptr, to remove any existing filters. - If takeOwnership is true, then the filter will be owned and deleted by the editor - when no longer needed. - */ - void setInputFilter (InputFilter* newFilter, bool takeOwnership); - - /** Returns the current InputFilter, as set by setInputFilter(). */ - InputFilter* getInputFilter() const noexcept { return inputFilter; } - - /** Sets limits on the characters that can be entered. - This is just a shortcut that passes an instance of the LengthAndCharacterRestriction - class to setInputFilter(). - - @param maxTextLength if this is > 0, it sets a maximum length limit; if 0, no - limit is set - @param allowedCharacters if this is non-empty, then only characters that occur in - this string are allowed to be entered into the editor. - */ - void setInputRestrictions (int maxTextLength, - const String& allowedCharacters = String()); - - void setKeyboardType (VirtualKeyboardType type) noexcept { keyboardType = type; } - - //============================================================================== - /** This abstract base class is implemented by LookAndFeel classes to provide - TextEditor drawing functionality. - */ - struct JUCE_API LookAndFeelMethods - { - virtual ~LookAndFeelMethods() {} - - virtual void fillSingleLineTextEditorBackground (Graphics&, int width, int height, SingleLineTextEditor&) = 0; - virtual void drawSingleLineTextEditorOutline (Graphics&, int width, int height, SingleLineTextEditor&) = 0; - - virtual CaretComponent* createSingleLineCaretComponent (Component* keyFocusOwner) = 0; - }; - - //============================================================================== - /** @internal */ - void paint (Graphics&) override; - /** @internal */ - void paintOverChildren (Graphics&) override; - /** @internal */ - void mouseDown (const MouseEvent&) override; - /** @internal */ - void mouseUp (const MouseEvent&) override; - /** @internal */ - void mouseDrag (const MouseEvent&) override; - /** @internal */ - void mouseDoubleClick (const MouseEvent&) override; - /** @internal */ - void mouseWheelMove (const MouseEvent&, const MouseWheelDetails&) override; - /** @internal */ - bool keyPressed (const KeyPress&) override; - /** @internal */ - bool keyStateChanged (bool) override; - /** @internal */ - void focusGained (FocusChangeType) override; - /** @internal */ - void focusLost (FocusChangeType) override; - /** @internal */ - void resized() override; - /** @internal */ - void enablementChanged() override; - /** @internal */ - void colourChanged() override; - /** @internal */ - void lookAndFeelChanged() override; - /** @internal */ - bool isTextInputActive() const override; - /** @internal */ - void setTemporaryUnderlining (const Array >&) override; - /** @internal */ - VirtualKeyboardType getKeyboardType() override { return keyboardType; } - -protected: - /** Used internally to dispatch a text-change message. */ - void textChanged(); - - /** Begins a new transaction in the UndoManager. */ - void newTransaction(); - - /** Can be overridden to intercept return key presses directly */ - virtual void returnPressed(); - - /** Can be overridden to intercept escape key presses directly */ - virtual void escapePressed(); - -private: - //============================================================================== - class Iterator; - JUCE_PUBLIC_IN_DLL_BUILD (class UniformTextSection) - class TextHolderComponent; - class InsertAction; - class RemoveAction; - friend class InsertAction; - friend class RemoveAction; - - std::unique_ptr textHolder; - - bool readOnly; - bool caretVisible; - bool popupMenuEnabled; - bool selectAllTextWhenFocused; - bool wasFocused; - bool tabKeyUsed; - bool menuActive; - bool valueTextNeedsUpdating; - bool consumeEscAndReturnKeys; - - UndoManager undoManager; - std::unique_ptr caret; - Range selection; - unsigned int lastTransactionTime; - Font currentFont; - mutable int totalNumChars; - int caretPosition; - OwnedArray sections; - String textToShowWhenEmpty; - Colour colourForTextWhenEmpty; - OptionalScopedPointer inputFilter; - Value textValue; - VirtualKeyboardType keyboardType; - Justification justification = Justification::centred; - - enum - { - notDragging, - draggingSelectionStart, - draggingSelectionEnd - } dragType; - - ListenerList listeners; - Array > underlinedSections; - - void moveCaret (int newCaretPos); - void moveCaretTo (int newPosition, bool isSelecting); - void recreateCaret(); - void handleCommandMessage (int) override; - void coalesceSimilarSections(); - void splitSection (int sectionIndex, int charToSplitAt); - void clearInternal (UndoManager*); - void insert (const String&, int insertIndex, const Font&, const Colour, UndoManager*, int newCaretPos); - void reinsert (int insertIndex, const OwnedArray&); - void remove (Range range, UndoManager*, int caretPositionToMoveTo); - void getCharPosition (int index, float& x, float& y, float& lineHeight) const; - void updateCaretPosition(); - void updateValueFromText(); - void textWasChangedByValue(); - int indexAtPosition (float x, float y); - int findWordBreakAfter (int position) const; - int findWordBreakBefore (int position) const; - bool moveCaretWithTransaction (int newPos, bool selecting); - friend class TextHolderComponent; - void drawContent (Graphics&); - float getWordWrapWidth() const; - void timerCallbackInt(); - void repaintText (Range); - bool undoOrRedo (bool shouldUndo); - UndoManager* getUndoManager() noexcept; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SingleLineTextEditor) -}; diff --git a/Modules/gin/geometry/geometry.h b/Modules/gin/geometry/geometry.h deleted file mode 100755 index 9646bd4..0000000 --- a/Modules/gin/geometry/geometry.h +++ /dev/null @@ -1,112 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -template -inline T square (T in) -{ - return in * in; -} - -//============================================================================== - -template -class Ellipse -{ -public: - Ellipse (T a_, T b_) : a (a_), b (b_) - { - } - - bool isPointOn (juce::Point pt, T accuracy = 0.00001) - { - return std::abs (1.0 - (square (pt.getX()) / square (a) + square (pt.getY()) / square (b))) < accuracy; - } - - bool isPointOutside (juce::Point pt) - { - return (square (pt.getX()) / square (a) + square (pt.getY()) / square (b)) > 1.0; - } - - bool isPointInside (juce::Point pt) - { - return (square (pt.getX()) / square (a) + square (pt.getY()) / square (b)) < 1.0; - } - - juce::Point pointAtAngle (T angle) - { - T x = (a * b) / std::sqrt (square (b) + square (a) * square (std::tan (angle))); - T y = (a * b) / std::sqrt (square (a) + square (b) / square (std::tan (angle))); - - while (angle < 0) angle += double_Pi * 2; - angle = std::fmod (angle, double_Pi * 2); - - if (angle >= double_Pi / 2 * 3) - { - y = -y; - } - else if (angle >= double_Pi) - { - y = -y; - x = -x; - } - else if (angle >= double_Pi / 2) - { - x = -x; - } - - return {x, y}; - } - - T a = 0, b = 0; -}; - -//============================================================================== -// Solves for the slope and intercept of a line. -template -bool solveLine (T x1, T y1, T x2, T y2, T& m, T& b) -{ - if (x2 != x1) - { - m = (y2 - y1) / (x2 - x1); - b = y2 - m * x2; - - return true; - } - else - { - m = 0; - b = 0; - - return false; - } -} - -template -bool solveLine (Line l, T& m, T& b) -{ - T x1 = l.getStartX(); - T x2 = l.getEndX(); - T y1 = l.getStartY(); - T y2 = l.getEndY(); - - if (x2 != x1) - { - m = (y2 - y1) / (x2 - x1); - b = y2 - m * x2; - - return true; - } - else - { - m = 0; - b = 0; - - return false; - } -} diff --git a/Modules/gin/gin.cpp b/Modules/gin/gin.cpp deleted file mode 100755 index d27ef6e..0000000 --- a/Modules/gin/gin.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -// Your project must contain an AppConfig.h file with your project-specific settings in it, -// and your header search path must make it accessible to the module's files. -#include "AppConfig.h" - -//============================================================================== - -#ifdef _WIN32 - #include - #include -#else - #include - #include - #include - #include - #include -#endif - -#ifdef __linux__ - #include - #include - #include - #include - #include -#endif - -#ifdef __APPLE__ - #import - #include - #include -#endif - -#if __clang__ || __GNUC__ - #include -#endif - -#include - -#include "gin.h" - -//============================================================================== - -#if __clang__ - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wconversion" - #pragma clang diagnostic ignored "-Wshadow" - #pragma clang diagnostic ignored "-Wunused-parameter" -#endif - -#if _MSC_VER - #pragma warning (push) - #pragma warning (disable: 4100) - #pragma warning (disable: 4127) - #pragma warning (disable: 4456) - #pragma warning (disable: 4457) - #pragma warning (disable: 4244) -#endif - -#include "3rdparty/avir/avir.h" -#if JUCE_INTEL - #include "3rdparty/avir/avir_float4_sse.h" -#endif - -#if __clang__ - #pragma clang diagnostic pop -#endif - -#if _MSC_VER - #pragma warning (pop) -#endif - -namespace gin -{ -using namespace juce; -using juce::Rectangle; -using juce::MemoryBlock; - -#include "utilities/asyncutilities.cpp" -#include "utilities/downloadmanager.cpp" -#include "utilities/elevatedfilecopy.cpp" -#include "utilities/filesystemwatcher.cpp" -#include "utilities/fileutilities.cpp" -#include "utilities/integrator.cpp" -#include "utilities/leastsquaresregression.cpp" -#include "utilities/linearregression.cpp" -#include "utilities/openstreetmaps.cpp" -#include "utilities/messagepack.cpp" -#include "utilities/realtimeasyncupdater.cpp" -#include "utilities/plist.cpp" -#include "utilities/sharedmemory.cpp" -#include "utilities/spline.cpp" -#include "utilities/systemsemaphore.cpp" -#include "utilities/threading.cpp" -#include "utilities/util.cpp" -#include "utilities/valuetreeobject.cpp" -#include "utilities/valuetreeutilities.cpp" - -#include "images/imageeffects.cpp" -#include "images/imageutilities.cpp" -#include "images/imageeffects_blending.cpp" -#include "images/imageeffects_stackblur.cpp" -#include "images/bmpimageformat.cpp" - -#include "components/componentviewer.cpp" -#include "components/ginlookandfeel.cpp" -#include "components/mapviewer.cpp" -#include "components/propertycomponents.cpp" -#include "components/singlelinetexteditor.cpp" - -} - -#include "utilities/equationparser.cpp" - -#if __clang__ - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wswitch-enum" -#endif - -#include "3rdparty/muParser/muParser.cpp" -#include "3rdparty/muParser/muParserBase.cpp" -#include "3rdparty/muParser/muParserBytecode.cpp" -#include "3rdparty/muParser/muParserCallback.cpp" -#include "3rdparty/muParser/muParserError.cpp" -#include "3rdparty/muParser/muParserTokenReader.cpp" - -#if __clang__ - #pragma clang diagnostic pop -#endif diff --git a/Modules/gin/gin.h b/Modules/gin/gin.h deleted file mode 100755 index e291945..0000000 --- a/Modules/gin/gin.h +++ /dev/null @@ -1,106 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - - -/******************************************************************************* - The block below describes the properties of this module, and is read by - the Projucer to automatically generate project code that uses it. - For details about the syntax and how to create or use a module, see the - JUCE Module Format.txt file. - - - BEGIN_JUCE_MODULE_DECLARATION - - ID: gin - vendor: Roland Rabien - version: 1.0.0 - name: Gin - description: Gin - website: www.rabiensoftware.com - license: BSD - - dependencies: juce_gui_basics juce_gui_extra juce_events - OSXFrameworks: Security - - END_JUCE_MODULE_DECLARATION - -*******************************************************************************/ - - -#pragma once - -#ifndef JUCE_MODULE_AVAILABLE_gin - /* If you fail to make sure that all your compile units are building JUCE with the same set of - option flags, then there's a risk that different compile units will treat the classes as having - different memory layouts, leading to very nasty memory corruption errors when they all get - linked together. That's why it's best to always include the Introjucer-generated AppConfig.h - file before any juce headers. - - Note that if you do have an AppConfig.h file and hit this warning, it means that it doesn't - contain the JUCE_MODULE_AVAILABLE_xxx flags, which are necessary for some inter-module - functionality to work correctly. In that case, you should either rebuild your AppConfig.h with - the latest introjucer, or fix it manually to contain these flags. - */ - #ifdef _MSC_VER - #pragma message ("Have you included your AppConfig.h file before including the JUCE headers?") - #else - #warning "Have you included your AppConfig.h file before including the JUCE headers?" - #endif -#endif - -//============================================================================== -#include -#include -#include -#include - -#include - -namespace gin -{ -using namespace juce; -using juce::Rectangle; -using juce::Component; - -#include "utilities/asyncutilities.h" -#include "utilities/coalescedtimer.h" -#include "utilities/downloadmanager.h" -#include "utilities/equationparser.h" -#include "utilities/util.h" -#include "utilities/easing.h" -#include "utilities/elevatedfilecopy.h" -#include "utilities/filesystemwatcher.h" -#include "utilities/fileutilities.h" -#include "utilities/integrator.h" -#include "utilities/lagrange.h" -#include "utilities/leastsquaresregression.h" -#include "utilities/linearregression.h" -#include "utilities/openstreetmaps.h" -#include "utilities/messagepack.h" -#include "utilities/plist.h" -#include "utilities/realtimeasyncupdater.h" -#include "utilities/sharedmemory.h" -#include "utilities/spline.h" -#include "utilities/systemsemaphore.h" -#include "utilities/threading.h" -#include "utilities/valuetreeobject.h" -#include "utilities/valuetreeutilities.h" - -#include "images/bmpimageformat.h" -#include "images/imageeffects.h" -#include "images/imageutilities.h" - -#include "geometry/geometry.h" - -#include "components/componentutils.h" -#include "components/componentviewer.h" -#include "components/ginlookandfeel.h" -#include "components/mapviewer.h" -#include "components/propertycomponents.h" -#include "components/singlelinetexteditor.h" - -} diff --git a/Modules/gin/gin.mm b/Modules/gin/gin.mm deleted file mode 100755 index bfe9057..0000000 --- a/Modules/gin/gin.mm +++ /dev/null @@ -1,9 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#include "gin.cpp" - diff --git a/Modules/gin/images/bmpimageformat.cpp b/Modules/gin/images/bmpimageformat.cpp deleted file mode 100755 index 8197048..0000000 --- a/Modules/gin/images/bmpimageformat.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -struct BMPHeader -{ - uint16 magic; - uint32 fileSize; - uint16 reserved1; - uint16 reserved2; - uint32 dataOffset; - uint32 headerSize; - int32 width; - int32 height; - uint16 planes; - uint16 bitsPerPixel; - uint32 compression; - uint32 imageDataSize; - int32 hPixelsPerMeter; - int32 vPixelsPerMeter; - uint32 coloursUsed; - uint32 coloursRequired; -}; - -String BMPImageFormat::getFormatName() -{ - return "Windows Bitmap"; -} - -bool BMPImageFormat::canUnderstand (InputStream& input) -{ - return input.readByte() == 'B' && - input.readByte() == 'M'; -} - -bool BMPImageFormat::usesFileExtension (const File& possibleFile) -{ - return possibleFile.hasFileExtension ("bmp"); -} - -Image BMPImageFormat::decodeImage (InputStream& input) -{ - BMPHeader hdr; - hdr.magic = uint16 (input.readShort()); - hdr.fileSize = uint32 (input.readInt()); - hdr.reserved1 = uint16 (input.readShort()); - hdr.reserved2 = uint16 (input.readShort()); - hdr.dataOffset = uint32 (input.readInt()); - hdr.headerSize = uint32 (input.readInt()); - hdr.width = int32 (input.readInt()); - hdr.height = int32 (input.readInt()); - hdr.planes = uint16 (input.readShort()); - hdr.bitsPerPixel = uint16 (input.readShort()); - hdr.compression = uint32 (input.readInt()); - hdr.imageDataSize = uint32 (input.readInt()); - hdr.hPixelsPerMeter = int32 (input.readInt()); - hdr.vPixelsPerMeter = int32 (input.readInt()); - hdr.coloursUsed = uint32 (input.readInt()); - hdr.coloursRequired = uint32 (input.readInt()); - - if (hdr.compression != 0 || (hdr.bitsPerPixel != 8 && hdr.bitsPerPixel != 24 && hdr.bitsPerPixel != 32)) - { - jassertfalse; // Unsupported BMP format - return Image(); - } - - if (hdr.bitsPerPixel == 8 && hdr.coloursUsed == 0) - hdr.coloursUsed = 256; - - Array colourTable; - - for (int i = 0; i < int (hdr.coloursUsed); i++) - { - uint8 b = uint8 (input.readByte()); - uint8 g = uint8 (input.readByte()); - uint8 r = uint8 (input.readByte()); - input.readByte(); - - colourTable.add (PixelARGB (255, r, g, b)); - } - - bool bottomUp = hdr.height < 0; - hdr.height = std::abs (hdr.height); - - Image img (Image::ARGB, int (hdr.width), int (hdr.height), true); - Image::BitmapData data (img, Image::BitmapData::writeOnly); - - input.setPosition (hdr.dataOffset); - - int bytesPerPixel = hdr.bitsPerPixel / 8; - int bytesPerRow = int (std::floor ((hdr.bitsPerPixel * hdr.width + 31) / 32.0) * 4); - - uint8* rowData = new uint8[size_t (bytesPerRow)]; - for (int y = 0; y < int (hdr.height); y++) - { - input.read (rowData, bytesPerRow); - - for (int x = 0; x < int (hdr.width); x++) - { - uint8* d = &rowData[x * bytesPerPixel]; - - PixelARGB* p = (PixelARGB*)data.getPixelPointer (x, int (bottomUp ? y : hdr.height - y - 1)); - if (hdr.bitsPerPixel == 8) - *p = colourTable[d[0]]; - else - p->setARGB (bytesPerPixel == 4 ? d[3] : 255, d[2], d[1], d[0]); - } - } - delete[] rowData; - - return img; -} - -bool BMPImageFormat::writeImageToStream (const Image& sourceImage, OutputStream& dst) -{ - Image img = sourceImage.convertedToFormat (Image::ARGB); - - dst.writeByte ('B'); - dst.writeByte ('M'); - dst.writeInt (40 + img.getWidth() * img.getHeight() * 4); - dst.writeShort (0); - dst.writeShort (0); - dst.writeInt (54); - dst.writeInt (40); - dst.writeInt (img.getWidth()); - dst.writeInt (img.getHeight()); - dst.writeShort (1); - dst.writeShort (32); - dst.writeInt (0); - dst.writeInt (img.getWidth() * img.getHeight() * 4); - dst.writeInt (2835); - dst.writeInt (2835); - dst.writeInt (0); - dst.writeInt (0); - - Image::BitmapData data (img, Image::BitmapData::readOnly); - for (int y = 0; y < img.getHeight(); y++) - { - for (int x = 0; x < img.getWidth(); x++) - { - PixelARGB* p = (PixelARGB*)data.getPixelPointer (x, int (img.getHeight() - y - 1)); - dst.writeByte (char (p->getBlue())); - dst.writeByte (char (p->getGreen())); - dst.writeByte (char (p->getRed())); - dst.writeByte (char (p->getAlpha())); - } - } - - return true; -} diff --git a/Modules/gin/images/bmpimageformat.h b/Modules/gin/images/bmpimageformat.h deleted file mode 100755 index cd212de..0000000 --- a/Modules/gin/images/bmpimageformat.h +++ /dev/null @@ -1,28 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -/** - Support for reading and writing Windows Bitmap files. Supports uncompressed - 8, 24 and 32 bit images. Always writes 32 bit images. That should be enough - to cover 99.9% of BMP files. Does not support 1, 4, 16 bit colour images or - images with RLE compression. - */ -class BMPImageFormat : public ImageFileFormat -{ -public: - String getFormatName() override; - - bool canUnderstand (InputStream& input) override; - - bool usesFileExtension (const File& possibleFile) override; - - Image decodeImage (InputStream& input) override; - - bool writeImageToStream (const Image& sourceImage, OutputStream& destStream) override; -}; diff --git a/Modules/gin/images/imageeffects.cpp b/Modules/gin/images/imageeffects.cpp deleted file mode 100755 index 803aadd..0000000 --- a/Modules/gin/images/imageeffects.cpp +++ /dev/null @@ -1,811 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#if JUCE_INTEL - #define USE_SSE 1 -#endif - -template -inline uint8 toByte (T v) -{ - if (v < 0) return 0; - if (v > 255) return 255; - return uint8 (v); -} - -inline uint8 getIntensity (uint8 r, uint8 g, uint8 b) -{ - return (uint8)((7471 * b + 38470 * g + 19595 * r) >> 16); -} - -inline uint8 computeAlpha (uint8 la, uint8 ra) -{ - return (uint8)(((la * (256 - (ra + (ra >> 7)))) >> 8) + ra); -} - -template -inline T blend (const T& c1, const T& c2) -{ - int a = c1.getAlpha(); - int invA = 255 - a; - - int r = ((c2.getRed() * invA) + (c1.getRed() * a)) / 256; - int g = ((c2.getGreen() * invA) + (c1.getGreen() * a)) / 256; - int b = ((c2.getBlue() * invA) + (c1.getBlue() * a)) / 256; - uint8 a2 = computeAlpha (c2.getAlpha(), c1.getAlpha()); - - T res; - res.setARGB (a2, toByte (r), toByte (g), toByte (b)); - return res; -} - -template -inline T2 convert (const T1& in) -{ - T2 out; - out.setARGB (in.getAlpha(), in.getRed(), in.getGreen(), in.getBlue()); - return out; -} - -//============================================================================== -template -void applyVignette (Image& img, float amountIn, float radiusIn, float fallOff, ThreadPool* threadPool) -{ - const int w = img.getWidth(); - const int h = img.getHeight(); - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - double outA = w * 0.5 * radiusIn; - double outB = h * 0.5 * radiusIn; - - double inA = outA * fallOff; - double inB = outB * fallOff; - - double cx = w * 0.5; - double cy = h * 0.5; - - double amount = 1.0 - amountIn; - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - Ellipse outE { outA, outB }; - Ellipse inE { inA, inB }; - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - uint8* p = data.getLinePointer (y); - - double dy = y - cy; - - for (int x = 0; x < w; x++) - { - double dx = x - cx; - - bool outside = outE.isPointOutside ({dx, dy}); - bool inside = inE.isPointInside ({dx, dy}); - - T* s = (T*)p; - - if (outside) - { - uint8 r = toByte (0.5 + (s->getRed() * amount)); - uint8 g = toByte (0.5 + (s->getGreen() * amount)); - uint8 b = toByte (0.5 + (s->getBlue() * amount)); - uint8 a = s->getAlpha(); - - s->setARGB (a, r, g, b); - } - else if (! inside) - { - double angle = std::atan2 (dy, dx); - - auto p1 = outE.pointAtAngle (angle); - auto p2 = inE.pointAtAngle (angle); - - auto l1 = Line ({dx,dy}, p2); - auto l2 = Line (p1, p2); - - double factor = 1.0 - (amountIn * jlimit (0.0, 1.0, l1.getLength() / l2.getLength())); - - uint8 r = toByte (0.5 + (s->getRed() * factor)); - uint8 g = toByte (0.5 + (s->getGreen() * factor)); - uint8 b = toByte (0.5 + (s->getBlue() * factor)); - uint8 a = s->getAlpha(); - - s->setARGB (a, r, g, b); - } - - p += data.pixelStride; - } - }); -} - -void applyVignette (Image& img, float amountIn, float radiusIn, float fallOff, ThreadPool* threadPool) -{ - if (img.getFormat() == Image::ARGB) applyVignette (img, amountIn, radiusIn, fallOff, threadPool); - else if (img.getFormat() == Image::RGB) applyVignette (img, amountIn, radiusIn, fallOff, threadPool); - else jassertfalse; -} - -template -void applySepia (Image& img, ThreadPool* threadPool) -{ - const int w = img.getWidth(); - const int h = img.getHeight(); - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - uint8* p = data.getLinePointer (y); - - for (int x = 0; x < w; x++) - { - PixelARGB* s = (PixelARGB*)p; - - uint8 r = s->getRed(); - uint8 g = s->getGreen(); - uint8 b = s->getBlue(); - uint8 a = s->getAlpha(); - - uint8 ro = toByte ((r * .393) + (g *.769) + (b * .189)); - uint8 go = toByte ((r * .349) + (g *.686) + (b * .168)); - uint8 bo = toByte ((r * .272) + (g *.534) + (b * .131)); - - s->setARGB (a, ro, go, bo); - - p += data.pixelStride; - } - }); -} - -void applySepia (Image& img, ThreadPool* threadPool) -{ - if (img.getFormat() == Image::ARGB) applySepia (img, threadPool); - else if (img.getFormat() == Image::RGB) applySepia (img, threadPool); - else jassertfalse; -} - -template -void applyGreyScale (Image& img, ThreadPool* threadPool) -{ - const int w = img.getWidth(); - const int h = img.getHeight(); - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - uint8* p = data.getLinePointer (y); - - for (int x = 0; x < w; x++) - { - T* s = (T*)p; - - uint8 r = s->getRed(); - uint8 g = s->getGreen(); - uint8 b = s->getBlue(); - uint8 a = s->getAlpha(); - - uint8 ro = toByte (r * 0.30 + 0.5); - uint8 go = toByte (g * 0.59 + 0.5); - uint8 bo = toByte (b * 0.11 + 0.5); - - s->setARGB (a, - toByte (ro + go + bo), - toByte (ro + go + bo), - toByte (ro + go + bo)); - - p += data.pixelStride; - } - }); -} - -void applyGreyScale (Image& img, ThreadPool* threadPool) -{ - if (img.getFormat() == Image::ARGB) applyGreyScale (img, threadPool); - else if (img.getFormat() == Image::RGB) applyGreyScale (img, threadPool); - else jassertfalse; -} - -template -void applySoften (Image& img, ThreadPool* threadPool) -{ - const int w = img.getWidth(); - const int h = img.getHeight(); - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - Image dst (img.getFormat(), w, h, true); - - Image::BitmapData srcData (img, Image::BitmapData::readOnly); - Image::BitmapData dstData (dst, Image::BitmapData::writeOnly); - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - for (int x = 0; x < w; x++) - { - int ro = 0, go = 0, bo = 0; - uint8 a = 0; - - for (int m = -1; m <= 1; m++) - { - for (int n = -1; n <= 1; n++) - { - int cx = jlimit (0, w - 1, x + m); - int cy = jlimit (0, h - 1, y + n); - - T* s = (T*) srcData.getPixelPointer (cx, cy); - - ro += s->getRed(); - go += s->getGreen(); - bo += s->getBlue(); - } - } - - T* s = (T*) srcData.getPixelPointer (x, y); - a = s->getAlpha(); - - T* d = (T*) dstData.getPixelPointer (x, y); - - d->setARGB (a, toByte (ro / 9), toByte (go / 9), toByte (bo / 9)); - } - }); - img = dst; -} - -void applySoften (Image& img, ThreadPool* threadPool) -{ - if (img.getFormat() == Image::ARGB) applySoften (img, threadPool); - else if (img.getFormat() == Image::RGB) applySoften (img, threadPool); - else jassertfalse; -} - -template -void applySharpen (Image& img, ThreadPool* threadPool) -{ - const int w = img.getWidth(); - const int h = img.getHeight(); - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - Image dst (img.getFormat(), w, h, true); - - Image::BitmapData srcData (img, Image::BitmapData::readOnly); - Image::BitmapData dstData (dst, Image::BitmapData::writeOnly); - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - for (int x = 0; x < w; x++) - { - auto getPixelPointer = [&] (int cx, int cy) -> T* - { - cx = jlimit (0, w - 1, cx); - cy = jlimit (0, h - 1, cy); - - return (T*) srcData.getPixelPointer (cx, cy); - }; - - int ro = 0, go = 0, bo = 0; - uint8 ao = 0; - - T* s = getPixelPointer (x, y); - - ro = s->getRed() * 5; - go = s->getGreen() * 5; - bo = s->getBlue() * 5; - ao = s->getAlpha(); - - s = getPixelPointer (x, y - 1); - ro -= s->getRed(); - go -= s->getGreen(); - bo -= s->getBlue(); - - s = getPixelPointer (x - 1, y); - ro -= s->getRed(); - go -= s->getGreen(); - bo -= s->getBlue(); - - s = getPixelPointer (x + 1, y); - ro -= s->getRed(); - go -= s->getGreen(); - bo -= s->getBlue(); - - s = getPixelPointer (x, y + 1); - ro -= s->getRed(); - go -= s->getGreen(); - bo -= s->getBlue(); - - T* d = (T*) dstData.getPixelPointer (x, y); - - d->setARGB (ao, toByte (ro), toByte (go), toByte (bo)); - } - }); - img = dst; -} - -void applySharpen (Image& img, ThreadPool* threadPool) -{ - if (img.getFormat() == Image::ARGB) applySharpen (img, threadPool); - else if (img.getFormat() == Image::RGB) applySharpen (img, threadPool); - else jassertfalse; -} - -template -void applyGamma (Image& img, float gamma, ThreadPool* threadPool) -{ - const int w = img.getWidth(); - const int h = img.getHeight(); - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - uint8* p = data.getLinePointer (y); - - for (int x = 0; x < w; x++) - { - T* s = (T*)p; - - uint8 r = s->getRed(); - uint8 g = s->getGreen(); - uint8 b = s->getBlue(); - uint8 a = s->getAlpha(); - - uint8 ro = toByte (std::pow (r / 255.0, gamma) * 255.0 + 0.5); - uint8 go = toByte (std::pow (g / 255.0, gamma) * 255.0 + 0.5); - uint8 bo = toByte (std::pow (b / 255.0, gamma) * 255.0 + 0.5); - - s->setARGB (a, ro, go, bo); - - p += data.pixelStride; - } - }); -} - -void applyGamma (Image& img, float gamma, ThreadPool* threadPool) -{ - if (img.getFormat() == Image::ARGB) applyGamma (img, gamma, threadPool); - else if (img.getFormat() == Image::RGB) applyGamma (img, gamma, threadPool); - else jassertfalse; -} - -template -void applyInvert (Image& img, ThreadPool* threadPool) -{ - const int w = img.getWidth(); - const int h = img.getHeight(); - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - uint8* p = data.getLinePointer (y); - - for (int x = 0; x < w; x++) - { - T* s = (T*)p; - - uint8 r = s->getRed(); - uint8 g = s->getGreen(); - uint8 b = s->getBlue(); - uint8 a = s->getAlpha(); - - uint8 ro = 255 - r; - uint8 go = 255 - g; - uint8 bo = 255 - b; - - s->setARGB (a, ro, go, bo); - - p += data.pixelStride; - } - }); -} - -void applyInvert (Image& img, ThreadPool* threadPool) -{ - if (img.getFormat() == Image::ARGB) applyInvert (img, threadPool); - else if (img.getFormat() == Image::RGB) applyInvert (img, threadPool); - else jassertfalse; -} - -template -void applyContrast (Image& img, float contrast, ThreadPool* threadPool) -{ - const int w = img.getWidth(); - const int h = img.getHeight(); - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - contrast = (100.0f + contrast) / 100.0f; - contrast = square (contrast); - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - uint8* p = data.getLinePointer (y); - - for (int x = 0; x < w; x++) - { - T* s = (T*)p; - - uint8 r = s->getRed(); - uint8 g = s->getGreen(); - uint8 b = s->getBlue(); - uint8 a = s->getAlpha(); - - double ro = (double) r / 255.0; - ro = ro - 0.5; - ro = ro * contrast; - ro = ro + 0.5; - ro = ro * 255.0; - - double go = (double) g / 255.0; - go = go - 0.5; - go = go * contrast; - go = go + 0.5; - go = go * 255.0; - - double bo = (double) b / 255.0; - bo = bo - 0.5; - bo = bo * contrast; - bo = bo + 0.5; - bo = bo * 255.0; - - ro = toByte (ro); - go = toByte (go); - bo = toByte (bo); - - s->setARGB (a, toByte (ro), toByte (go), toByte (bo)); - - p += data.pixelStride; - } - }); -} - -void applyContrast (Image& img, float contrast, ThreadPool* threadPool) -{ - if (img.getFormat() == Image::ARGB) applyContrast (img, contrast, threadPool); - else if (img.getFormat() == Image::RGB) applyContrast (img, contrast, threadPool); - else jassertfalse; -} - -template -void applyBrightnessContrast (Image& img, float brightness, float contrast, ThreadPool* threadPool) -{ - const int w = img.getWidth(); - const int h = img.getHeight(); - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - double multiply = 1; - double divide = 1; - - if (contrast < 0) - { - multiply = contrast + 100; - divide = 100; - } - else if (contrast > 0) - { - multiply = 100; - divide = 100 - contrast; - } - else - { - multiply = 1; - divide = 1; - } - - uint8* rgbTable = new uint8[65536]; - - if (divide == 0) - { - for (int intensity = 0; intensity < 256; intensity++) - { - if (intensity + brightness < 128) - rgbTable[intensity] = 0; - else - rgbTable[intensity] = 255; - } - } - else if (divide == 100) - { - for (int intensity = 0; intensity < 256; intensity++) - { - int shift = int ((intensity - 127) * multiply / divide + 127 - intensity + brightness); - - for (int col = 0; col < 256; col++) - { - int index = (intensity * 256) + col; - rgbTable[index] = toByte (col + shift); - } - } - } - else - { - for (int intensity = 0; intensity < 256; intensity++) - { - int shift = int ((intensity - 127 + brightness) * multiply / divide + 127 - intensity); - - for (int col = 0; col < 256; col++) - { - int index = (intensity * 256) + col; - rgbTable[index] = toByte (col + shift); - } - } - } - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - uint8* p = data.getLinePointer (y); - - for (int x = 0; x < w; x++) - { - T* s = (T*)p; - - uint8 r = s->getRed(); - uint8 g = s->getGreen(); - uint8 b = s->getBlue(); - uint8 a = s->getAlpha(); - - if (divide == 0) - { - int i = getIntensity (toByte (r), toByte (g), toByte (b)); - uint8 c = rgbTable[i]; - - s->setARGB (a, c, c, c); - } - else - { - int i = getIntensity (toByte (r), toByte (g), toByte (b)); - int shiftIndex = i * 256; - - uint8 ro = rgbTable[shiftIndex + r]; - uint8 go = rgbTable[shiftIndex + g]; - uint8 bo = rgbTable[shiftIndex + b]; - - ro = toByte (ro); - go = toByte (go); - bo = toByte (bo); - - s->setARGB (a, ro, go, bo); - } - - p += data.pixelStride; - } - }); - - delete[] rgbTable; -} - -void applyBrightnessContrast (Image& img, float brightness, float contrast, ThreadPool* threadPool) -{ - if (img.getFormat() == Image::ARGB) applyBrightnessContrast (img, brightness, contrast, threadPool); - else if (img.getFormat() == Image::RGB) applyBrightnessContrast (img, brightness, contrast, threadPool); - else jassertfalse; -} - -template -void applyHueSaturationLightness (Image& img, float hueIn, float saturation, float lightness, ThreadPool* threadPool) -{ - const int w = img.getWidth(); - const int h = img.getHeight(); - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - if (saturation > 100) - saturation = ((saturation - 100) * 3) + 100; - saturation = (saturation * 1024) / 100; - - hueIn /= 360.0f; - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - uint8* p = data.getLinePointer (y); - - for (int x = 0; x < w; x++) - { - T* s = (T*)p; - - uint8 r = s->getRed(); - uint8 g = s->getGreen(); - uint8 b = s->getBlue(); - uint8 a = s->getAlpha(); - - int intensity = getIntensity (toByte (r), toByte (g), toByte (b)); - int ro = toByte (int (intensity * 1024 + (r - intensity) * saturation) >> 10); - int go = toByte (int (intensity * 1024 + (g - intensity) * saturation) >> 10); - int bo = toByte (int (intensity * 1024 + (b - intensity) * saturation) >> 10); - - Colour c (toByte (ro), toByte (go), toByte (bo)); - float hue = c.getHue(); - hue += hueIn; - - while (hue < 0.0f) hue += 1.0f; - while (hue >= 1.0f) hue -= 1.0f; - - c = Colour::fromHSV (hue, c.getSaturation(), c.getBrightness(), float (a)); - ro = c.getRed(); - go = c.getGreen(); - bo = c.getBlue(); - - ro = toByte (ro); - go = toByte (go); - bo = toByte (bo); - - s->setARGB (a, toByte (ro), toByte (go), toByte (bo)); - - if (lightness > 0) - { - auto blended = blend (PixelARGB (toByte ((lightness * 255) / 100 * (a / 255.0)), 255, 255, 255), convert (*s)); - *s = convert (blended); - } - else if (lightness < 0) - { - auto blended = blend (PixelARGB (toByte ((-lightness * 255) / 100 * (a / 255.0)), 0, 0, 0), convert (*s)); - *s = convert (blended); - } - - p += data.pixelStride; - } - }); -} - -void applyHueSaturationLightness (Image& img, float hue, float saturation, float lightness, ThreadPool* threadPool) -{ - if (img.getFormat() == Image::ARGB) applyHueSaturationLightness (img, hue, saturation, lightness, threadPool); - else if (img.getFormat() == Image::RGB) applyHueSaturationLightness (img, hue, saturation, lightness, threadPool); - else jassertfalse; -} - -Image applyResize (const Image& src, int width, int height) -{ - Image dst (src.getFormat(), width, height, true); - - Image::BitmapData srcData (src, Image::BitmapData::readOnly); - Image::BitmapData dstData (dst, Image::BitmapData::readWrite); - - int channels = 0; - if (src.getFormat() == Image::ARGB) channels = 4; - else if (src.getFormat() == Image::RGB) channels = 3; - else if (src.getFormat() == Image::SingleChannel) channels = 1; - else return {}; - - // JUCE images may have padding at the end of each scan line. - // Avir expects the image data to be packed. So we need to - // pack and unpack the image data before and after resizing. - HeapBlock srcPacked (src.getWidth() * src.getHeight() * channels); - HeapBlock dstPacked (dst.getWidth() * dst.getHeight() * channels); - - uint8* rawSrc = srcPacked.getData(); - uint8* rawDst = dstPacked.getData(); - - for (int y = 0; y < src.getHeight(); y++) - memcpy (rawSrc + y * src.getWidth() * channels, - srcData.getLinePointer (y), - (size_t) (src.getWidth() * channels)); - - #if USE_SSE - avir::CImageResizer imageResizer (8); - imageResizer.resizeImage (rawSrc, src.getWidth(), src.getHeight(), 0, - rawDst, dst.getWidth(), dst.getHeight(), channels, 0); - #else - avir::CImageResizer<> imageResizer (8); - imageResizer.resizeImage (rawSrc, src.getWidth(), src.getHeight(), 0, - rawDst, dst.getWidth(), dst.getHeight(), channels, 0); - #endif - - for (int y = 0; y < dst.getHeight(); y++) - memcpy (dstData.getLinePointer (y), - rawDst + y * dst.getWidth() * channels, - (size_t) (dst.getWidth() * channels)); - - return dst; -} - -Image applyResize (const Image& src, float factor) -{ - return applyResize (src, - roundToInt (factor * src.getWidth()), - roundToInt (factor * src.getHeight())); -} - -template -void applyGradientMap (Image& img, const ColourGradient& gradient, ThreadPool* threadPool) -{ - const int w = img.getWidth(); - const int h = img.getHeight(); - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - uint8* p = data.getLinePointer (y); - - for (int x = 0; x < w; x++) - { - T* s = (T*)p; - - uint8 r = s->getRed(); - uint8 g = s->getGreen(); - uint8 b = s->getBlue(); - uint8 a = s->getAlpha(); - - uint8 ro = toByte (r * 0.30 + 0.5); - uint8 go = toByte (g * 0.59 + 0.5); - uint8 bo = toByte (b * 0.11 + 0.5); - - float proportion = float (ro + go + bo) / 256.0f; - - auto c = gradient.getColourAtPosition (proportion); - - s->setARGB (a, - c.getRed(), - c.getGreen(), - c.getBlue()); - - p += data.pixelStride; - } - }); -} - -void applyGradientMap (Image& img, const ColourGradient& gradient, ThreadPool* threadPool) -{ - if (img.getFormat() == Image::ARGB) applyGradientMap (img, gradient, threadPool); - else if (img.getFormat() == Image::RGB) applyGradientMap (img, gradient, threadPool); - else jassertfalse; -} - -void applyGradientMap (Image& img, const Colour c1, const Colour c2, ThreadPool* threadPool) -{ - ColourGradient g; - g.addColour (0.0, c1); - g.addColour (1.0, c2); - - applyGradientMap (img, g, threadPool); -} - -template -void applyColour (Image& img, Colour c, ThreadPool* threadPool) -{ - const int w = img.getWidth(); - const int h = img.getHeight(); - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - uint8 r = c.getRed(); - uint8 g = c.getGreen(); - uint8 b = c.getBlue(); - uint8 a = c.getAlpha(); - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - uint8* p = data.getLinePointer (y); - - for (int x = 0; x < w; x++) - { - T* s = (T*)p; - s->setARGB (a, r, g, b); - p += data.pixelStride; - } - }); -} - -void applyColour (Image& img, Colour c, ThreadPool* threadPool) -{ - if (img.getFormat() == Image::ARGB) applyColour (img, c, threadPool); - else if (img.getFormat() == Image::RGB) applyColour (img, c, threadPool); - else jassertfalse; -} - diff --git a/Modules/gin/images/imageeffects.h b/Modules/gin/images/imageeffects.h deleted file mode 100755 index bc68185..0000000 --- a/Modules/gin/images/imageeffects.h +++ /dev/null @@ -1,117 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -//============================================================================== -/** Apply vignette - * - \param amount Amount to darken outside of vignette. 0 no darkening. 1 is black. - \param radius Size of vignette. 1 size of image. 0 is 0 size. - \param falloff Relative size of inner boundry of vignette 0,1 - */ -void applyVignette (Image& img, float amount, float radius, float falloff, ThreadPool* threadPool = nullptr); - -/** Make it look old */ -void applySepia (Image& img, ThreadPool* threadPool = nullptr); - -/** Converts image to B/W, heavier weighting towards greens */ -void applyGreyScale (Image& img, ThreadPool* threadPool = nullptr); - -/** Softens an image */ -void applySoften (Image& img, ThreadPool* threadPool = nullptr); - -/** Sharpens an image */ -void applySharpen (Image& img, ThreadPool* threadPool = nullptr); - -void applyGamma (Image& img, float gamma, ThreadPool* threadPool = nullptr); - -/** Inverts colours of an image */ -void applyInvert (Image& img, ThreadPool* threadPool = nullptr); - -/** Adjust contrast of an image - * - \param contrast Amount to adjust contrast. Negative values increase, positive values increase -*/ -void applyContrast (Image& img, float contrast, ThreadPool* threadPool = nullptr); - -/** Adjust brightness and contrast of an image - * - \param brightness Amount to adjust brightness -100,100 - \param contrast Amount to adjust contrast -100,100 - */ -void applyBrightnessContrast (Image& img, float brightness, float contrast, ThreadPool* threadPool = nullptr); - -/** Adjust hue, saturation and lightness of an image - * - \param hue Amount to adjust hue -180,180 - \param saturation Amount to adjust saturation 0,200 - \param lightness Amount to adjust lightness -100,100 - */ -void applyHueSaturationLightness (Image& img, float hue, float saturation, float lightness, ThreadPool* threadPool = nullptr); - -/** A very fast blur. This is a compromise between Gaussian Blur and Box blur. - It creates much better looking blurs than Box Blur, but is 7x faster than some Gaussian Blur - implementations. - * - \param radius from 2 to 254 - */ -void applyStackBlur (Image& img, int radius); - -/** A very high quality image resize using a bank of sinc - * function-based fractional delay filters */ -Image applyResize (const Image& img, int width, int height); - -Image applyResize (const Image& img, float factor); - -/** GradientMap a image. Brightness gets remapped to colour on a gradient. - */ -void applyGradientMap (Image& img, const ColourGradient& gradient, ThreadPool* threadPool = nullptr); - -void applyGradientMap (Image& img, const Colour c1, const Colour c2, ThreadPool* threadPool = nullptr); - -/** Set an image to a solid colour - */ -void applyColour (Image& img, Colour c, ThreadPool* threadPool = nullptr); - -/** Blend two images - */ - -enum BlendMode -{ - Normal, - Lighten, - Darken, - Multiply, - Average, - Add, - Subtract, - Difference, - Negation, - Screen, - Exclusion, - Overlay, - SoftLight, - HardLight, - ColorDodge, - ColorBurn, - LinearDodge, - LinearBurn, - LinearLight, - VividLight, - PinLight, - HardMix, - Reflect, - Glow, - Phoenix, -}; - -void applyBlend (Image& dst, const Image& src, BlendMode mode, float alpha = 1.0f, juce::Point position = {}, ThreadPool* threadPool = nullptr); - -void applyBlend (Image& dst, BlendMode mode, Colour c, ThreadPool* threadPool = nullptr); - - diff --git a/Modules/gin/images/imageeffects_blending.cpp b/Modules/gin/images/imageeffects_blending.cpp deleted file mode 100755 index 9046c0c..0000000 --- a/Modules/gin/images/imageeffects_blending.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -inline uint8 channelBlendNormal (int A, int) { return ((uint8)(A)); } -inline uint8 channelBlendLighten (int A, int B) { return ((uint8)((B > A) ? B : A)); } -inline uint8 channelBlendDarken (int A, int B) { return ((uint8)((B > A) ? A : B)); } -inline uint8 channelBlendMultiply (int A, int B) { return ((uint8)((A * B) / 255)); } -inline uint8 channelBlendAverage (int A, int B) { return ((uint8)((A + B) / 2)); } -inline uint8 channelBlendAdd (int A, int B) { return ((uint8)(jmin (255, (A + B)))); } -inline uint8 channelBlendSubtract (int A, int B) { return ((uint8)((A + B < 255) ? 0 : (A + B - 255))); } -inline uint8 channelBlendDifference (int A, int B) { return ((uint8)(std::abs (A - B))); } -inline uint8 channelBlendNegation (int A, int B) { return ((uint8)(255 - std::abs (255 - A - B))); } -inline uint8 channelBlendScreen (int A, int B) { return ((uint8)(255 - (((255 - A) * (255 - B)) >> 8))); } -inline uint8 channelBlendExclusion (int A, int B) { return ((uint8)(A + B - 2 * A * B / 255)); } -inline uint8 channelBlendOverlay (int A, int B) { return ((uint8)((B < 128) ? (2 * A * B / 255) : (255 - 2 * (255 - A) * (255 - B) / 255))); } -inline uint8 channelBlendSoftLight (int A, int B) { return ((uint8)((B < 128) ? (2 * ((A >> 1) + 64)) * ((float)B / 255) : (255 - (2 * (255 - ((A >> 1) + 64)) * (float)(255 - B) / 255)))); } -inline uint8 channelBlendHardLight (int A, int B) { return (channelBlendOverlay (B,A)); } -inline uint8 channelBlendColorDodge (int A, int B) { return ((uint8)((B == 255) ? B : jmin (255, ((A << 8 ) / (255 - B))))); } -inline uint8 channelBlendColorBurn (int A, int B) { return ((uint8)((B == 0) ? B : jmax (0, (255 - ((255 - A) << 8 ) / B)))); } -inline uint8 channelBlendLinearDodge (int A, int B) { return (channelBlendAdd (A, B)); } -inline uint8 channelBlendLinearBurn (int A, int B) { return (channelBlendSubtract (A, B)); } -inline uint8 channelBlendLinearLight (int A, int B) { return ((uint8)(B < 128) ? channelBlendLinearBurn (A,(2 * B)) : channelBlendLinearDodge (A, (2 * (B - 128)))); } -inline uint8 channelBlendVividLight (int A, int B) { return ((uint8)(B < 128) ? channelBlendColorBurn (A,(2 * B)) : channelBlendColorDodge (A, (2 * (B - 128)))); } -inline uint8 channelBlendPinLight (int A, int B) { return ((uint8)(B < 128) ? channelBlendDarken (A,(2 * B)) : channelBlendLighten (A, (2 * (B - 128)))); } -inline uint8 channelBlendHardMix (int A, int B) { return ((uint8)((channelBlendVividLight (A, B) < 128) ? 0:255)); } -inline uint8 channelBlendReflect (int A, int B) { return ((uint8)((B == 255) ? B : jmin (255, (A * A / (255 - B))))); } -inline uint8 channelBlendGlow (int A, int B) { return (channelBlendReflect (B, A)); } -inline uint8 channelBlendPhoenix (int A, int B) { return ((uint8)(jmin (A, B) - jmax (A, B) + 255)); } - -inline uint8 channelBlendAlpha (uint8 A, uint8 B, float O) -{ - return ((uint8)(O * A + (1 - O) * B)); -} - -template -void applyBlend (Image& dst, const Image& src, float alpha, juce::Point position, ThreadPool* threadPool) -{ - auto rcLower = Rectangle (0, 0, dst.getWidth(), dst.getHeight()); - auto rcUpper = Rectangle (position.x, position.y, src.getWidth(), src.getHeight()); - - auto rcOverlap = rcLower.getIntersection (rcUpper); - if (rcOverlap.isEmpty()) - return; - - int w = rcOverlap.getWidth(); - int h = rcOverlap.getHeight(); - - int cropX = position.x < 0 ? -position.x : 0; - int cropY = position.y < 0 ? -position.y : 0; - - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - Image::BitmapData srcData (src, Image::BitmapData::readOnly); - Image::BitmapData dstData (dst, Image::BitmapData::readWrite); - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - uint8* pSrc = srcData.getLinePointer (cropY + y); - uint8* pDst = dstData.getLinePointer (rcOverlap.getY() + y); - - pSrc += srcData.pixelStride * cropX; - pDst += dstData.pixelStride * rcOverlap.getX(); - - for (int x = 0; x < w; x++) - { - T* ac = (T*)pSrc; - T* bc = (T*)pDst; - - uint8 ar = ac->getRed(); - uint8 ag = ac->getGreen(); - uint8 ab = ac->getBlue(); - uint8 aa = ac->getAlpha(); - - uint8 br = bc->getRed(); - uint8 bg = bc->getGreen(); - uint8 bb = bc->getBlue(); - uint8 ba = bc->getAlpha(); - - if (ba == 255) - { - float pixelAlpha = alpha * aa / 255.0f; - - br = channelBlendAlpha (F (ar, br), br, pixelAlpha); - bg = channelBlendAlpha (F (ag, bg), bg, pixelAlpha); - bb = channelBlendAlpha (F (ab, bb), bb, pixelAlpha); - } - else - { - float srcAlpha = alpha * aa / 255.0f; - float dstAlpha = ba / 255.0f; - - float outAlpha = srcAlpha + dstAlpha * (1.0f - srcAlpha); - - if (outAlpha == 0.0) - { - br = 0; - bg = 0; - bb = 0; - } - else - { - uint8 r = F (ar, br); - uint8 g = F (ag, bg); - uint8 b = F (ab, bb); - - br = uint8 ((r * srcAlpha + br * dstAlpha * (1.0f - srcAlpha)) / outAlpha); - bg = uint8 ((g * srcAlpha + bg * dstAlpha * (1.0f - srcAlpha)) / outAlpha); - bb = uint8 ((b * srcAlpha + bb * dstAlpha * (1.0f - srcAlpha)) / outAlpha); - } - } - - bc->setARGB (ba, br, bg, bb); - - pSrc += srcData.pixelStride; - pDst += dstData.pixelStride; - } - }); -} - -template -void applyBlend (Image& dst, const Image& src, BlendMode mode, float alpha, juce::Point position, ThreadPool* threadPool) -{ - switch (mode) - { - case Normal: applyBlend (dst, src, alpha, position, threadPool); break; - case Lighten: applyBlend (dst, src, alpha, position, threadPool); break; - case Darken: applyBlend (dst, src, alpha, position, threadPool); break; - case Multiply: applyBlend (dst, src, alpha, position, threadPool); break; - case Average: applyBlend (dst, src, alpha, position, threadPool); break; - case Add: applyBlend (dst, src, alpha, position, threadPool); break; - case Subtract: applyBlend (dst, src, alpha, position, threadPool); break; - case Difference: applyBlend (dst, src, alpha, position, threadPool); break; - case Negation: applyBlend (dst, src, alpha, position, threadPool); break; - case Screen: applyBlend (dst, src, alpha, position, threadPool); break; - case Exclusion: applyBlend (dst, src, alpha, position, threadPool); break; - case Overlay: applyBlend (dst, src, alpha, position, threadPool); break; - case SoftLight: applyBlend (dst, src, alpha, position, threadPool); break; - case HardLight: applyBlend (dst, src, alpha, position, threadPool); break; - case ColorDodge: applyBlend (dst, src, alpha, position, threadPool); break; - case ColorBurn: applyBlend (dst, src, alpha, position, threadPool); break; - case LinearDodge: applyBlend (dst, src, alpha, position, threadPool); break; - case LinearBurn: applyBlend (dst, src, alpha, position, threadPool); break; - case LinearLight: applyBlend (dst, src, alpha, position, threadPool); break; - case VividLight: applyBlend (dst, src, alpha, position, threadPool); break; - case PinLight: applyBlend (dst, src, alpha, position, threadPool); break; - case HardMix: applyBlend (dst, src, alpha, position, threadPool); break; - case Reflect: applyBlend (dst, src, alpha, position, threadPool); break; - case Glow: applyBlend (dst, src, alpha, position, threadPool); break; - case Phoenix: applyBlend (dst, src, alpha, position, threadPool); break; - } -} - -void applyBlend (Image& dst, const Image& src, BlendMode mode, float alpha, juce::Point position, ThreadPool* threadPool) -{ - if (src.getFormat() != dst.getFormat()) - { - Image copy = src.createCopy(); - copy = copy.convertedToFormat (dst.getFormat()); - - if (src.getFormat() == Image::ARGB) applyBlend (dst, copy, mode, alpha, position, threadPool); - else if (src.getFormat() == Image::RGB) applyBlend (dst, copy, mode, alpha, position, threadPool); - else jassertfalse; - } - else - { - if (src.getFormat() == Image::ARGB) applyBlend (dst, src, mode, alpha, position, threadPool); - else if (src.getFormat() == Image::RGB) applyBlend (dst, src, mode, alpha, position, threadPool); - else jassertfalse; - } -} - -template -void applyBlend (Image& dst, Colour c, ThreadPool* threadPool) -{ - int w = dst.getWidth(); - int h = dst.getHeight(); - - threadPool = (w >= 256 || h >= 256) ? threadPool : nullptr; - - Image::BitmapData dstData (dst, Image::BitmapData::readWrite); - - uint8 ar = c.getRed(); - uint8 ag = c.getGreen(); - uint8 ab = c.getBlue(); - uint8 aa = c.getAlpha(); - - multiThreadedFor (0, h, 1, threadPool, [&] (int y) - { - uint8* pDst = dstData.getLinePointer (y); - - for (int x = 0; x < w; x++) - { - T* bc = (T*)pDst; - - uint8 br = bc->getRed(); - uint8 bg = bc->getGreen(); - uint8 bb = bc->getBlue(); - uint8 ba = bc->getAlpha(); - - if (ba == 255) - { - float pixelAlpha = aa / 255.0f; - - br = channelBlendAlpha (F (ar, br), br, pixelAlpha); - bg = channelBlendAlpha (F (ag, bg), bg, pixelAlpha); - bb = channelBlendAlpha (F (ab, bb), bb, pixelAlpha); - } - else - { - float srcAlpha = aa / 255.0f; - float dstAlpha = ba / 255.0f; - - float outAlpha = srcAlpha + dstAlpha * (1.0f - srcAlpha); - - if (outAlpha == 0.0) - { - br = 0; - bg = 0; - bb = 0; - } - else - { - uint8 r = F (ar, br); - uint8 g = F (ag, bg); - uint8 b = F (ab, bb); - - br = uint8 ((r * srcAlpha + br * dstAlpha * (1.0f - srcAlpha)) / outAlpha); - bg = uint8 ((g * srcAlpha + bg * dstAlpha * (1.0f - srcAlpha)) / outAlpha); - bb = uint8 ((b * srcAlpha + bb * dstAlpha * (1.0f - srcAlpha)) / outAlpha); - } - } - - bc->setARGB (ba, br, bg, bb); - - pDst += dstData.pixelStride; - } - }); -} - -template -void applyBlend (Image& dst, BlendMode mode, Colour c, ThreadPool* threadPool) -{ - switch (mode) - { - case Normal: applyBlend (dst, c, threadPool); break; - case Lighten: applyBlend (dst, c, threadPool); break; - case Darken: applyBlend (dst, c, threadPool); break; - case Multiply: applyBlend (dst, c, threadPool); break; - case Average: applyBlend (dst, c, threadPool); break; - case Add: applyBlend (dst, c, threadPool); break; - case Subtract: applyBlend (dst, c, threadPool); break; - case Difference: applyBlend (dst, c, threadPool); break; - case Negation: applyBlend (dst, c, threadPool); break; - case Screen: applyBlend (dst, c, threadPool); break; - case Exclusion: applyBlend (dst, c, threadPool); break; - case Overlay: applyBlend (dst, c, threadPool); break; - case SoftLight: applyBlend (dst, c, threadPool); break; - case HardLight: applyBlend (dst, c, threadPool); break; - case ColorDodge: applyBlend (dst, c, threadPool); break; - case ColorBurn: applyBlend (dst, c, threadPool); break; - case LinearDodge: applyBlend (dst, c, threadPool); break; - case LinearBurn: applyBlend (dst, c, threadPool); break; - case LinearLight: applyBlend (dst, c, threadPool); break; - case VividLight: applyBlend (dst, c, threadPool); break; - case PinLight: applyBlend (dst, c, threadPool); break; - case HardMix: applyBlend (dst, c, threadPool); break; - case Reflect: applyBlend (dst, c, threadPool); break; - case Glow: applyBlend (dst, c, threadPool); break; - case Phoenix: applyBlend (dst, c, threadPool); break; - } -} - -void applyBlend (Image& dst, BlendMode mode, Colour c, ThreadPool* threadPool) -{ - if (dst.getFormat() == Image::ARGB) applyBlend (dst, mode, c, threadPool); - else if (dst.getFormat() == Image::RGB) applyBlend (dst, mode, c, threadPool); - else jassertfalse; -} diff --git a/Modules/gin/images/imageeffects_stackblur.cpp b/Modules/gin/images/imageeffects_stackblur.cpp deleted file mode 100755 index ed6c4e7..0000000 --- a/Modules/gin/images/imageeffects_stackblur.cpp +++ /dev/null @@ -1,717 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -static unsigned short const stackblur_mul[255] = -{ - 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512, - 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512, - 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456, - 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512, - 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328, - 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456, - 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335, - 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512, - 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405, - 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328, - 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271, - 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456, - 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388, - 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335, - 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292, - 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259 -}; - -static unsigned char const stackblur_shr[255] = -{ - 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, - 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 -}; - -static void applyStackBlurBW (Image& img, unsigned int radius) -{ - const unsigned int w = (unsigned int)img.getWidth(); - const unsigned int h = (unsigned int)img.getHeight(); - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - radius = jlimit (2u, 254u, radius); - - unsigned char stack[(254 * 2 + 1) * 1]; - - unsigned int x, y, xp, yp, i, sp, stack_start; - - unsigned char* stack_ptr = nullptr; - unsigned char* src_ptr = nullptr; - unsigned char* dst_ptr = nullptr; - - unsigned long sum, sum_in, sum_out; - - unsigned int wm = w - 1; - unsigned int hm = h - 1; - unsigned int w1 = (unsigned int) data.lineStride; - unsigned int div = (unsigned int) (radius * 2) + 1; - unsigned int mul_sum = stackblur_mul[radius]; - unsigned char shr_sum = stackblur_shr[radius]; - - for (y = 0; y < h; ++y) - { - sum = sum_in = sum_out = 0; - - src_ptr = data.getLinePointer (int (y)); - - for (i = 0; i <= radius; ++i) - { - stack_ptr = &stack[i]; - stack_ptr[0] = src_ptr[0]; - sum += src_ptr[0] * (i + 1); - sum_out += src_ptr[0]; - } - - for (i = 1; i <= radius; ++i) - { - if (i <= wm) - src_ptr += 1; - - stack_ptr = &stack[1 * (i + radius)]; - stack_ptr[0] = src_ptr[0]; - sum += src_ptr[0] * (radius + 1 - i); - sum_in += src_ptr[0]; - } - - sp = radius; - xp = radius; - if (xp > wm) - xp = wm; - - src_ptr = data.getLinePointer (int (y)) + (unsigned int)data.pixelStride * xp; - dst_ptr = data.getLinePointer (int (y)); - - for (x = 0; x < w; ++x) - { - dst_ptr[0] = (unsigned char)((sum * mul_sum) >> shr_sum); - dst_ptr += 1; - - sum -= sum_out; - - stack_start = sp + div - radius; - - if (stack_start >= div) - stack_start -= div; - - stack_ptr = &stack[1 * stack_start]; - - sum_out -= stack_ptr[0]; - - if (xp < wm) - { - src_ptr += 1; - ++xp; - } - - stack_ptr[0] = src_ptr[0]; - - sum_in += src_ptr[0]; - sum += sum_in; - - ++sp; - if (sp >= div) - sp = 0; - - stack_ptr = &stack[sp*1]; - - sum_out += stack_ptr[0]; - sum_in -= stack_ptr[0]; - } - } - - for (x = 0; x < w; ++x) - { - sum = sum_in = sum_out = 0; - - src_ptr = data.getLinePointer (0) + (unsigned int)data.pixelStride * x; - - for (i = 0; i <= radius; ++i) - { - stack_ptr = &stack[i * 1]; - stack_ptr[0] = src_ptr[0]; - sum += src_ptr[0] * (i + 1); - sum_out += src_ptr[0]; - } - - for (i = 1; i <= radius; ++i) - { - if (i <= hm) - src_ptr += w1; - - stack_ptr = &stack[1 * (i + radius)]; - stack_ptr[0] = src_ptr[0]; - sum += src_ptr[0] * (radius + 1 - i); - sum_in += src_ptr[0]; - } - - sp = radius; - yp = radius; - if (yp > hm) - yp = hm; - - src_ptr = data.getLinePointer (int (yp)) + (unsigned int)data.pixelStride * x; - dst_ptr = data.getLinePointer (0) + (unsigned int)data.pixelStride * x; - - for (y = 0; y < h; ++y) - { - dst_ptr[0] = (unsigned char)((sum * mul_sum) >> shr_sum); - dst_ptr += w1; - - sum -= sum_out; - - stack_start = sp + div - radius; - if (stack_start >= div) - stack_start -= div; - - stack_ptr = &stack[1 * stack_start]; - - sum_out -= stack_ptr[0]; - - if (yp < hm) - { - src_ptr += w1; - ++yp; - } - - stack_ptr[0] = src_ptr[0]; - - sum_in += src_ptr[0]; - sum += sum_in; - - ++sp; - if (sp >= div) - sp = 0; - - stack_ptr = &stack[sp * 1]; - - sum_out += stack_ptr[0]; - sum_in -= stack_ptr[0]; - } - } -} - -static void applyStackBlurRGB (Image& img, unsigned int radius) -{ - const unsigned int w = (unsigned int)img.getWidth(); - const unsigned int h = (unsigned int)img.getHeight(); - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - radius = jlimit (2u, 254u, radius); - - unsigned char stack[(254 * 2 + 1) * 3]; - - unsigned int x, y, xp, yp, i, sp, stack_start; - - unsigned char* stack_ptr = nullptr; - unsigned char* src_ptr = nullptr; - unsigned char* dst_ptr = nullptr; - - unsigned long sum_r, sum_g, sum_b, sum_in_r, sum_in_g, sum_in_b, - sum_out_r, sum_out_g, sum_out_b; - - unsigned int wm = w - 1; - unsigned int hm = h - 1; - unsigned int w3 = (unsigned int) data.lineStride; - unsigned int div = (unsigned int)(radius * 2) + 1; - unsigned int mul_sum = stackblur_mul[radius]; - unsigned char shr_sum = stackblur_shr[radius]; - - for (y = 0; y < h; ++y) - { - sum_r = sum_g = sum_b = - sum_in_r = sum_in_g = sum_in_b = - sum_out_r = sum_out_g = sum_out_b = 0; - - src_ptr = data.getLinePointer (int (y)); - - for (i = 0; i <= radius; ++i) - { - stack_ptr = &stack[3 * i]; - stack_ptr[0] = src_ptr[0]; - stack_ptr[1] = src_ptr[1]; - stack_ptr[2] = src_ptr[2]; - sum_r += src_ptr[0] * (i + 1); - sum_g += src_ptr[1] * (i + 1); - sum_b += src_ptr[2] * (i + 1); - sum_out_r += src_ptr[0]; - sum_out_g += src_ptr[1]; - sum_out_b += src_ptr[2]; - } - - for (i = 1; i <= radius; ++i) - { - if (i <= wm) - src_ptr += 3; - - stack_ptr = &stack[3 * (i + radius)]; - stack_ptr[0] = src_ptr[0]; - stack_ptr[1] = src_ptr[1]; - stack_ptr[2] = src_ptr[2]; - sum_r += src_ptr[0] * (radius + 1 - i); - sum_g += src_ptr[1] * (radius + 1 - i); - sum_b += src_ptr[2] * (radius + 1 - i); - sum_in_r += src_ptr[0]; - sum_in_g += src_ptr[1]; - sum_in_b += src_ptr[2]; - } - - sp = radius; - xp = radius; - if (xp > wm) - xp = wm; - - src_ptr = data.getLinePointer (int (y)) + (unsigned int)data.pixelStride * xp; - dst_ptr = data.getLinePointer (int (y)); - - for (x = 0; x < w; ++x) - { - dst_ptr[0] = (unsigned char)((sum_r * mul_sum) >> shr_sum); - dst_ptr[1] = (unsigned char)((sum_g * mul_sum) >> shr_sum); - dst_ptr[2] = (unsigned char)((sum_b * mul_sum) >> shr_sum); - dst_ptr += 3; - - sum_r -= sum_out_r; - sum_g -= sum_out_g; - sum_b -= sum_out_b; - - stack_start = sp + div - radius; - - if (stack_start >= div) - stack_start -= div; - - stack_ptr = &stack[3 * stack_start]; - - sum_out_r -= stack_ptr[0]; - sum_out_g -= stack_ptr[1]; - sum_out_b -= stack_ptr[2]; - - if (xp < wm) - { - src_ptr += 3; - ++xp; - } - - stack_ptr[0] = src_ptr[0]; - stack_ptr[1] = src_ptr[1]; - stack_ptr[2] = src_ptr[2]; - - sum_in_r += src_ptr[0]; - sum_in_g += src_ptr[1]; - sum_in_b += src_ptr[2]; - sum_r += sum_in_r; - sum_g += sum_in_g; - sum_b += sum_in_b; - - ++sp; - if (sp >= div) - sp = 0; - - stack_ptr = &stack[sp*3]; - - sum_out_r += stack_ptr[0]; - sum_out_g += stack_ptr[1]; - sum_out_b += stack_ptr[2]; - sum_in_r -= stack_ptr[0]; - sum_in_g -= stack_ptr[1]; - sum_in_b -= stack_ptr[2]; - } - } - - for (x = 0; x < w; ++x) - { - sum_r = sum_g = sum_b = - sum_in_r = sum_in_g = sum_in_b = - sum_out_r = sum_out_g = sum_out_b = 0; - - src_ptr = data.getLinePointer (0) + (unsigned int)data.pixelStride * x; - - for (i = 0; i <= radius; ++i) - { - stack_ptr = &stack[i * 3]; - stack_ptr[0] = src_ptr[0]; - stack_ptr[1] = src_ptr[1]; - stack_ptr[2] = src_ptr[2]; - sum_r += src_ptr[0] * (i + 1); - sum_g += src_ptr[1] * (i + 1); - sum_b += src_ptr[2] * (i + 1); - sum_out_r += src_ptr[0]; - sum_out_g += src_ptr[1]; - sum_out_b += src_ptr[2]; - } - - for (i = 1; i <= radius; ++i) - { - if (i <= hm) - src_ptr += w3; - - stack_ptr = &stack[3 * (i + radius)]; - stack_ptr[0] = src_ptr[0]; - stack_ptr[1] = src_ptr[1]; - stack_ptr[2] = src_ptr[2]; - sum_r += src_ptr[0] * (radius + 1 - i); - sum_g += src_ptr[1] * (radius + 1 - i); - sum_b += src_ptr[2] * (radius + 1 - i); - sum_in_r += src_ptr[0]; - sum_in_g += src_ptr[1]; - sum_in_b += src_ptr[2]; - } - - sp = radius; - yp = radius; - if (yp > hm) - yp = hm; - - src_ptr = data.getLinePointer (int (yp)) + (unsigned int)data.pixelStride * x; - dst_ptr = data.getLinePointer (0) + (unsigned int)data.pixelStride * x; - - for (y = 0; y < h; ++y) - { - dst_ptr[0] = (unsigned char)((sum_r * mul_sum) >> shr_sum); - dst_ptr[1] = (unsigned char)((sum_g * mul_sum) >> shr_sum); - dst_ptr[2] = (unsigned char)((sum_b * mul_sum) >> shr_sum); - dst_ptr += w3; - - sum_r -= sum_out_r; - sum_g -= sum_out_g; - sum_b -= sum_out_b; - - stack_start = sp + div - radius; - if (stack_start >= div) - stack_start -= div; - - stack_ptr = &stack[3 * stack_start]; - - sum_out_r -= stack_ptr[0]; - sum_out_g -= stack_ptr[1]; - sum_out_b -= stack_ptr[2]; - - if (yp < hm) - { - src_ptr += w3; - ++yp; - } - - stack_ptr[0] = src_ptr[0]; - stack_ptr[1] = src_ptr[1]; - stack_ptr[2] = src_ptr[2]; - - sum_in_r += src_ptr[0]; - sum_in_g += src_ptr[1]; - sum_in_b += src_ptr[2]; - sum_r += sum_in_r; - sum_g += sum_in_g; - sum_b += sum_in_b; - - ++sp; - if (sp >= div) - sp = 0; - - stack_ptr = &stack[sp * 3]; - - sum_out_r += stack_ptr[0]; - sum_out_g += stack_ptr[1]; - sum_out_b += stack_ptr[2]; - sum_in_r -= stack_ptr[0]; - sum_in_g -= stack_ptr[1]; - sum_in_b -= stack_ptr[2]; - } - } -} - -static void applyStackBlurARGB (Image& img, unsigned int radius) -{ - const unsigned int w = (unsigned int)img.getWidth(); - const unsigned int h = (unsigned int)img.getHeight(); - - Image::BitmapData data (img, Image::BitmapData::readWrite); - - radius = jlimit (2u, 254u, radius); - - unsigned char stack[(254 * 2 + 1) * 4]; - - unsigned int x, y, xp, yp, i, sp, stack_start; - - unsigned char* stack_ptr = nullptr; - unsigned char* src_ptr = nullptr; - unsigned char* dst_ptr = nullptr; - - unsigned long sum_r, sum_g, sum_b, sum_a, sum_in_r, sum_in_g, sum_in_b, sum_in_a, - sum_out_r, sum_out_g, sum_out_b, sum_out_a; - - unsigned int wm = w - 1; - unsigned int hm = h - 1; - unsigned int w4 = (unsigned int) data.lineStride; - unsigned int div = (unsigned int)(radius * 2) + 1; - unsigned int mul_sum = stackblur_mul[radius]; - unsigned char shr_sum = stackblur_shr[radius]; - - for (y = 0; y < h; ++y) - { - sum_r = sum_g = sum_b = sum_a = - sum_in_r = sum_in_g = sum_in_b = sum_in_a = - sum_out_r = sum_out_g = sum_out_b = sum_out_a = 0; - - src_ptr = data.getLinePointer (int (y)); - - for (i = 0; i <= radius; ++i) - { - stack_ptr = &stack[4 * i]; - stack_ptr[0] = src_ptr[0]; - stack_ptr[1] = src_ptr[1]; - stack_ptr[2] = src_ptr[2]; - stack_ptr[3] = src_ptr[3]; - sum_r += src_ptr[0] * (i + 1); - sum_g += src_ptr[1] * (i + 1); - sum_b += src_ptr[2] * (i + 1); - sum_a += src_ptr[3] * (i + 1); - sum_out_r += src_ptr[0]; - sum_out_g += src_ptr[1]; - sum_out_b += src_ptr[2]; - sum_out_a += src_ptr[3]; - } - - for (i = 1; i <= radius; ++i) - { - if (i <= wm) - src_ptr += 4; - - stack_ptr = &stack[4 * (i + radius)]; - stack_ptr[0] = src_ptr[0]; - stack_ptr[1] = src_ptr[1]; - stack_ptr[2] = src_ptr[2]; - stack_ptr[3] = src_ptr[3]; - sum_r += src_ptr[0] * (radius + 1 - i); - sum_g += src_ptr[1] * (radius + 1 - i); - sum_b += src_ptr[2] * (radius + 1 - i); - sum_a += src_ptr[3] * (radius + 1 - i); - sum_in_r += src_ptr[0]; - sum_in_g += src_ptr[1]; - sum_in_b += src_ptr[2]; - sum_in_a += src_ptr[3]; - } - - sp = radius; - xp = radius; - if (xp > wm) - xp = wm; - - src_ptr = data.getLinePointer (int (y)) + (unsigned int)data.pixelStride * xp; - dst_ptr = data.getLinePointer (int (y)); - - for (x = 0; x < w; ++x) - { - dst_ptr[0] = (unsigned char)((sum_r * mul_sum) >> shr_sum); - dst_ptr[1] = (unsigned char)((sum_g * mul_sum) >> shr_sum); - dst_ptr[2] = (unsigned char)((sum_b * mul_sum) >> shr_sum); - dst_ptr[3] = (unsigned char)((sum_a * mul_sum) >> shr_sum); - dst_ptr += 4; - - sum_r -= sum_out_r; - sum_g -= sum_out_g; - sum_b -= sum_out_b; - sum_a -= sum_out_a; - - stack_start = sp + div - radius; - - if (stack_start >= div) - stack_start -= div; - - stack_ptr = &stack[4 * stack_start]; - - sum_out_r -= stack_ptr[0]; - sum_out_g -= stack_ptr[1]; - sum_out_b -= stack_ptr[2]; - sum_out_a -= stack_ptr[3]; - - if (xp < wm) - { - src_ptr += 4; - ++xp; - } - - stack_ptr[0] = src_ptr[0]; - stack_ptr[1] = src_ptr[1]; - stack_ptr[2] = src_ptr[2]; - stack_ptr[3] = src_ptr[3]; - - sum_in_r += src_ptr[0]; - sum_in_g += src_ptr[1]; - sum_in_b += src_ptr[2]; - sum_in_a += src_ptr[3]; - sum_r += sum_in_r; - sum_g += sum_in_g; - sum_b += sum_in_b; - sum_a += sum_in_a; - - ++sp; - if (sp >= div) - sp = 0; - - stack_ptr = &stack[sp*4]; - - sum_out_r += stack_ptr[0]; - sum_out_g += stack_ptr[1]; - sum_out_b += stack_ptr[2]; - sum_out_a += stack_ptr[3]; - sum_in_r -= stack_ptr[0]; - sum_in_g -= stack_ptr[1]; - sum_in_b -= stack_ptr[2]; - sum_in_a -= stack_ptr[3]; - } - } - - for (x = 0; x < w; ++x) - { - sum_r = sum_g = sum_b = sum_a = - sum_in_r = sum_in_g = sum_in_b = sum_in_a = - sum_out_r = sum_out_g = sum_out_b = sum_out_a = 0; - - src_ptr = data.getLinePointer (0) + (unsigned int)data.pixelStride * x; - - for (i = 0; i <= radius; ++i) - { - stack_ptr = &stack[i * 4]; - stack_ptr[0] = src_ptr[0]; - stack_ptr[1] = src_ptr[1]; - stack_ptr[2] = src_ptr[2]; - stack_ptr[3] = src_ptr[3]; - sum_r += src_ptr[0] * (i + 1); - sum_g += src_ptr[1] * (i + 1); - sum_b += src_ptr[2] * (i + 1); - sum_a += src_ptr[3] * (i + 1); - sum_out_r += src_ptr[0]; - sum_out_g += src_ptr[1]; - sum_out_b += src_ptr[2]; - sum_out_a += src_ptr[3]; - } - - for (i = 1; i <= radius; ++i) - { - if (i <= hm) - src_ptr += w4; - - stack_ptr = &stack[4 * (i + radius)]; - stack_ptr[0] = src_ptr[0]; - stack_ptr[1] = src_ptr[1]; - stack_ptr[2] = src_ptr[2]; - stack_ptr[3] = src_ptr[3]; - sum_r += src_ptr[0] * (radius + 1 - i); - sum_g += src_ptr[1] * (radius + 1 - i); - sum_b += src_ptr[2] * (radius + 1 - i); - sum_a += src_ptr[3] * (radius + 1 - i); - sum_in_r += src_ptr[0]; - sum_in_g += src_ptr[1]; - sum_in_b += src_ptr[2]; - sum_in_a += src_ptr[3]; - } - - sp = radius; - yp = radius; - if (yp > hm) - yp = hm; - - src_ptr = data.getLinePointer (int (yp)) + (unsigned int)data.pixelStride * x; - dst_ptr = data.getLinePointer (0) + (unsigned int)data.pixelStride * x; - - for (y = 0; y < h; ++y) - { - dst_ptr[0] = (unsigned char)((sum_r * mul_sum) >> shr_sum); - dst_ptr[1] = (unsigned char)((sum_g * mul_sum) >> shr_sum); - dst_ptr[2] = (unsigned char)((sum_b * mul_sum) >> shr_sum); - dst_ptr[3] = (unsigned char)((sum_a * mul_sum) >> shr_sum); - dst_ptr += w4; - - sum_r -= sum_out_r; - sum_g -= sum_out_g; - sum_b -= sum_out_b; - sum_a -= sum_out_a; - - stack_start = sp + div - radius; - if (stack_start >= div) - stack_start -= div; - - stack_ptr = &stack[4 * stack_start]; - - sum_out_r -= stack_ptr[0]; - sum_out_g -= stack_ptr[1]; - sum_out_b -= stack_ptr[2]; - sum_out_a -= stack_ptr[3]; - - if (yp < hm) - { - src_ptr += w4; - ++yp; - } - - stack_ptr[0] = src_ptr[0]; - stack_ptr[1] = src_ptr[1]; - stack_ptr[2] = src_ptr[2]; - stack_ptr[3] = src_ptr[3]; - - sum_in_r += src_ptr[0]; - sum_in_g += src_ptr[1]; - sum_in_b += src_ptr[2]; - sum_in_a += src_ptr[3]; - sum_r += sum_in_r; - sum_g += sum_in_g; - sum_b += sum_in_b; - sum_a += sum_in_a; - - ++sp; - if (sp >= div) - sp = 0; - - stack_ptr = &stack[sp * 4]; - - sum_out_r += stack_ptr[0]; - sum_out_g += stack_ptr[1]; - sum_out_b += stack_ptr[2]; - sum_out_a += stack_ptr[3]; - sum_in_r -= stack_ptr[0]; - sum_in_g -= stack_ptr[1]; - sum_in_b -= stack_ptr[2]; - sum_in_a -= stack_ptr[3]; - } - } -} - -// The Stack Blur Algorithm was invented by Mario Klingemann, -// mario@quasimondo.com and described here: -// http://incubator.quasimondo.com/processing/fast_blur_deluxe.php - -// Stackblur algorithm by Mario Klingemann -// Details here: -// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html -// C++ implemenation base from: -// https://gist.github.com/benjamin9999/3809142 -// http://www.antigrain.com/__code/include/agg_blur.h.html -void applyStackBlur (Image& img, int radius) -{ - if (img.getFormat() == Image::ARGB) applyStackBlurARGB (img, (unsigned int)radius); - if (img.getFormat() == Image::RGB) applyStackBlurRGB (img, (unsigned int)radius); - if (img.getFormat() == Image::SingleChannel) applyStackBlurBW (img, (unsigned int)radius); -} diff --git a/Modules/gin/images/imageutilities.cpp b/Modules/gin/images/imageutilities.cpp deleted file mode 100755 index 975f741..0000000 --- a/Modules/gin/images/imageutilities.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/*============================================================================== - - Copyright 2019 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -juce::Image rasterizeSVG ( juce::String svgText, int w, int h ) -{ - Image img ( Image::ARGB, w, h, true ); - - if ( auto svg = XmlDocument::parse ( svgText ) ) - { - const MessageManagerLock mmLock; - - auto drawable = Drawable::createFromSVG ( *svg ); - - Graphics g ( img ); - drawable->drawWithin ( g, Rectangle ( float ( w ), float ( h ) ), 0, 1.f ); - } - - return img; -} diff --git a/Modules/gin/images/imageutilities.h b/Modules/gin/images/imageutilities.h deleted file mode 100755 index 1efbbbf..0000000 --- a/Modules/gin/images/imageutilities.h +++ /dev/null @@ -1,10 +0,0 @@ -/*============================================================================== - - Copyright 2019 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -juce::Image rasterizeSVG (juce::String svgText, int w, int h); \ No newline at end of file diff --git a/Modules/gin/utilities/asyncutilities.cpp b/Modules/gin/utilities/asyncutilities.cpp deleted file mode 100755 index f900cac..0000000 --- a/Modules/gin/utilities/asyncutilities.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -//============================================================================== - -struct BlockingData -{ - std::function func; -}; - -static void* blockingCallback (void* param) -{ - auto data = (BlockingData*)param; - - if (data->func) - data->func(); - - delete data; - return nullptr; -} - -void callOnMainThreadBlocking ( std::function func ) -{ - auto data = new BlockingData(); - data->func = func; - - MessageManager::getInstance()->callFunctionOnMessageThread (blockingCallback, data); -} diff --git a/Modules/gin/utilities/asyncutilities.h b/Modules/gin/utilities/asyncutilities.h deleted file mode 100755 index 29dbfdd..0000000 --- a/Modules/gin/utilities/asyncutilities.h +++ /dev/null @@ -1,40 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -class LambdaTimer : public Timer -{ -public: - LambdaTimer (std::function func = nullptr) : onTimer (func) {} - - std::function onTimer; - -private: - void timerCallback() override - { - if (onTimer) - onTimer(); - } -}; - -class LambdaAsyncUpdater : public AsyncUpdater -{ -public: - LambdaAsyncUpdater (std::function func) : onAsyncUpdate (func) {} - - std::function onAsyncUpdate; - -private: - void handleAsyncUpdate () override - { - if (onAsyncUpdate) - onAsyncUpdate(); - } -}; - -void callOnMainThreadBlocking ( std::function func ); diff --git a/Modules/gin/utilities/coalescedtimer.h b/Modules/gin/utilities/coalescedtimer.h deleted file mode 100755 index 2704ee3..0000000 --- a/Modules/gin/utilities/coalescedtimer.h +++ /dev/null @@ -1,89 +0,0 @@ -/*============================================================================== - - Copyright 2020 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -class CoalescedTimer -{ -public: - CoalescedTimer () = default; - - void startTimer (int ms) - { - stopTimer(); - - delay = ms; - sharedTimers->add (this); - } - - void startTimerHz (int hz) - { - if (hz > 0) - startTimer (1000 / hz); - else - stopTimer(); - } - - void stopTimer() - { - sharedTimers->remove (this); - delay = 0; - } - - std::function onTimer; - -private: - class SharedTimer : public Timer - { - public: - void timerCallback() override - { - for (auto t : timers) - if (t->onTimer) - t->onTimer (); - } - - Array timers; - }; - - class SharedTimers - { - public: - void add (CoalescedTimer* t) - { - auto itr = timers.find (t->delay); - if (itr == timers.end()) - { - auto st = std::make_unique(); - st->timers.add (t); - st->startTimer (t->delay); - - timers[t->delay] = std::move (st); - } - else - { - itr->second->timers.add (t); - } - } - - void remove (CoalescedTimer* t) - { - auto itr = timers.find (t->delay); - if (itr != timers.end()) - { - itr->second->timers.removeFirstMatchingValue (t); - if (itr->second->timers.size() == 0) - timers.erase (t->delay); - } - } - - std::map> timers; - }; - - int delay = 0; - SharedResourcePointer sharedTimers; -}; diff --git a/Modules/gin/utilities/downloadmanager.cpp b/Modules/gin/utilities/downloadmanager.cpp deleted file mode 100755 index 568da59..0000000 --- a/Modules/gin/utilities/downloadmanager.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/*============================================================================== - -Copyright 2018 by Roland Rabien -For more information visit www.rabiensoftware.com - -==============================================================================*/ - -DownloadManager::DownloadManager (int connect, int shutdown) - : connectTimeout (connect), shutdownTimeout (shutdown) -{ -} - -DownloadManager::~DownloadManager() -{ - cancelAllDownloads(); -} - -void DownloadManager::setConcurrentDownloadLimit (int limit) -{ - maxDownloads = limit; - triggerNextDownload(); -} - -void DownloadManager::triggerNextDownload() -{ - for (int i = 0; i < downloads.size() && runningDownloads < maxDownloads; i++) - { - auto d = downloads[i]; - if (! d->started) - { - runningDownloads++; - d->started = true; - d->startThread (priority); - } - } -} - -DownloadManager::DownloadResult DownloadManager::blockingDownload (String url, String postData, String extraHeaders) -{ - return blockingDownload (URL (url).withPOSTData (postData), extraHeaders); -} - -DownloadManager::DownloadResult DownloadManager::blockingDownload (URL url, String extraHeaders) -{ - #if JUCE_WINDOWS - auto headerList = StringArray::fromTokens (extraHeaders, "\n", ""); - headerList.add ("Accept-Encoding: gzip"); - extraHeaders = headerList.joinIntoString ("\n"); - #endif - - Download download (*this); - download.async = false; - download.result.url = url; - download.headers = extraHeaders; - download.result.downloadId = 0; - download.completionCallback = nullptr; - download.progressCallback = nullptr; - - download.run(); - - return download.result; -} - -int DownloadManager::startAsyncDownload (String url, String postData, - std::function completionCallback, - std::function progressCallback, - String extraHeaders) -{ - return startAsyncDownload (URL (url).withPOSTData (postData), completionCallback, progressCallback, extraHeaders); -} - -int DownloadManager::startAsyncDownload (URL url, - std::function completionCallback, - std::function progressCallback, - String extraHeaders) -{ - #if JUCE_WINDOWS - // macOS does this automatically - if (gzipDeflate) - { - auto headerList = StringArray::fromTokens (extraHeaders, "\n", ""); - headerList.add ("Accept-Encoding: gzip"); - extraHeaders = headerList.joinIntoString ("\n"); - } - #endif - - auto download = new Download (*this); - download->result.url = url; - download->headers = extraHeaders; - download->result.downloadId = ++nextId; - download->completionCallback = completionCallback; - download->progressCallback = progressCallback; - - downloads.add (download); - - triggerNextDownload(); - - return download->result.downloadId; -} - -void DownloadManager::cancelAllDownloads() -{ - runningDownloads = 0; - downloads.clear(); -} - -void DownloadManager::cancelDownload (int downloadId) -{ - for (int i = downloads.size(); --i >= 0;) - { - if (downloads[i]->result.downloadId == downloadId) - { - if (downloads[i]->isThreadRunning()) - runningDownloads--; - - downloads.remove (i); - triggerNextDownload(); - - if (downloads.size() == 0 && queueFinishedCallback) - queueFinishedCallback(); - - break; - } - } -} - -void DownloadManager::downloadFinished (Download* download) -{ - runningDownloads--; - downloads.removeObject (download); - - triggerNextDownload(); - - if (downloads.size() == 0 && queueFinishedCallback) - queueFinishedCallback(); -} - -void DownloadManager::pauseDownloads (bool p) -{ - pause = p; -} - -//============================================================================== -DownloadManager::Download::~Download() -{ - // Cancel any blocking reads - if (is != nullptr) - is->cancel(); - - // Wait a long time before cancelling, WebInputStream could be stuck in - // connect. Unlikely but possible. - if (async) - stopThread (owner.shutdownTimeout); -} - -void DownloadManager::Download::run() -{ - int attemps = owner.retryLimit + 1; - while (attemps-- && ! threadShouldExit()) - { - result.attempts++; - if (tryDownload()) - break; - - if (owner.retryDelay > 0) - wait (roundToInt (owner.retryDelay * 1000)); - - while (owner.pause.get()) - wait (500); - } - - if (async && ! threadShouldExit()) - { - // Get a weak reference to self, to check if we get deleted before - // async call happens. - WeakReference self = this; - MessageManager::callAsync ([self] - { - if (self != nullptr) - self->completionCallback (self->result); - if (self != nullptr) - self->owner.downloadFinished (self); - // DownloadManager has now delete us, don't do anything else - }); - } -} - -bool DownloadManager::Download::tryDownload() -{ - // Use post if we have post data - const bool post = result.url.getPostData().isNotEmpty(); - - if ((is = std::make_unique (result.url, post)) != nullptr) - { - if (headers.isNotEmpty()) - is->withExtraHeaders (headers); - is->withConnectionTimeout (owner.connectTimeout); - - if (is->connect (nullptr)) - { - // Save headers and http response code - result.httpCode = is->getStatusCode(); - result.responseHeaders = is->getResponseHeaders(); - - auto keys = result.responseHeaders.getAllKeys(); - auto vals = result.responseHeaders.getAllValues(); - - MemoryOutputStream os (result.data, false); - - lastBytesSent = 0; - lastProgress = Time::getMillisecondCounter(); - int64 downloaded = 0; - int64 totalLength = is->getTotalLength(); - - // For chunked http encoding, overall length may not be given - if (totalLength < 0) - totalLength = std::numeric_limits::max(); - - // Download all data - char buffer[128 * 1000]; - while (! is->isExhausted() && ! threadShouldExit() && downloaded < totalLength) - { - int64 toRead = jmin (int64 (sizeof (buffer)), int64 (owner.downloadBlockSize), totalLength - downloaded); - - int read = is->read (buffer, int (toRead)); - - if (owner.pause.get()) - { - result.ok = false; - break; - } - else if (read > 0) - { - os.write (buffer, size_t (read)); - downloaded += read; - result.ok = (is->isExhausted() || downloaded == totalLength) && result.httpCode == 200; - - updateProgress (downloaded, totalLength, false); - } - else if (read == 0 && is->isExhausted()) - { - // For chunked encoding, assume we have it all, otherwise check the length - if (totalLength < std::numeric_limits::max()) - result.ok = (totalLength == downloaded) && result.httpCode == 200; - else - result.ok = result.httpCode == 200; - - break; - } - else - { - result.ok = false; - break; - } - } - - updateProgress (downloaded, totalLength, true); - } - } - - #if JUCE_WINDOWS - // Decompress the gzip encoded data. This happens automatically on macOS - if (result.ok && result.responseHeaders["Content-Encoding"] == "gzip") - { - MemoryInputStream mis (result.data, true); - GZIPDecompressorInputStream gis (&mis, false, GZIPDecompressorInputStream::gzipFormat); - - result.data.reset(); - - while (! gis.isExhausted()) - { - char buffer[10 * 1024]; - int read = gis.read (buffer, sizeof (buffer)); - if (read > 0) - result.data.append (buffer, size_t (read)); - } - } - #endif - - return result.ok; -} - -void DownloadManager::Download::updateProgress (int64 current, int64 total, bool forceNotification) -{ - if (progressCallback) - { - // Update progress no more than once per second - uint32 now = Time::getMillisecondCounter(); - if ((now >= lastProgress + uint32 (owner.downloadIntervalMS)) || forceNotification) - { - int64 delta = current - lastBytesSent; - lastBytesSent = current; - lastProgress = now; - - if (delta > 0) - { - // Get a weak reference to self, to check if we get deleted before - // async call happens. - WeakReference self = this; - MessageManager::callAsync ([self, current, total, delta] - { - if (self != nullptr) - self->progressCallback (current, total, delta); - }); - } - } - } -} diff --git a/Modules/gin/utilities/downloadmanager.h b/Modules/gin/utilities/downloadmanager.h deleted file mode 100755 index 8c178b6..0000000 --- a/Modules/gin/utilities/downloadmanager.h +++ /dev/null @@ -1,162 +0,0 @@ -/*============================================================================== - -Copyright 2018 by Roland Rabien -For more information visit www.rabiensoftware.com - -==============================================================================*/ - -#pragma once - -#include "util.h" - -/** - - Downloads files to a memory block and then calls a lambda - on the message thread with the results. Does not block the - message thread while establishing the HTTP connect like - URL::downloadToFile - - */ -class DownloadManager -{ -public: - //============================================================================== - DownloadManager (int connectTimeout = 30 * 1000, int shutdownTimeout = 30 * 1000); - ~DownloadManager(); - - /** This callback is called every time all downloads are finished */ - void setQueueFinishedCallback (std::function callback) - { - queueFinishedCallback = callback; - } - - /** How long connecting is given before it times out */ - void setConnectTimeout (int timeout) { connectTimeout = timeout; } - - /** If a download fails, how long many times it should retry */ - void setRetryLimit (int limit) { retryLimit = limit; } - - /** If a download fails, how long to wait until trying again */ - void setRetryDelay (double seconds) { retryDelay = seconds; } - - /** Maximum number of downloads to allow at once */ - void setConcurrentDownloadLimit (int l); - - /** Number of items in download queue */ - int getNumberOfDownloads() { return downloads.size(); } - - /** Set download thread priority. Does not affect priority of - already running threads */ - void setThreadPriority (int p) { priority = p; } - - /** Sets minimum time between download progress callbacks in milliseconds */ - void setProgressInterval (int ms) { downloadIntervalMS = jmax (1, ms); } - - /** Sets the block size of chunks to download. Progress callbacks and - cancelling downloads can only happen between these blocks. Max size is 128 KB */ - void setDownloadBlockSize (int bs) { downloadBlockSize = jlimit (1, 128 * 1000, bs); } - - int getNumDownloadsInQueue() { return downloads.size(); } - - /** If enabled, will request the server sends the data compressed - This only has effect on windows. On macOS it is handled by the system libraries - and is always on. - */ - void enableGzipDeflate (bool e) { gzipDeflate = e; } - - /** Pause / resume all downloads. This actually stops any running downloads - and then restarts them when unpaused. You will loose some downloaded data - that will need to be redownloaded. */ - void pauseDownloads (bool); - - //============================================================================== - struct DownloadResult - { - URL url; - int downloadId = 0; - int attempts = 0; - - juce::MemoryBlock data; - - bool ok = false; - int httpCode = 0; - StringPairArray responseHeaders; - }; - - //============================================================================== - /** Starts a download and returns the download id which can be used to cancel the download - - progressCallback returns current amount downloaded, total amount to download, and amount - downloaded since last callback. Note that for http chunk encoding total size is unknown - and will be maximum int64 value. - */ - int startAsyncDownload (String url, String postData, - std::function completionCallback, - std::function progressCallback = nullptr, - String extraHeaders = {}); - - int startAsyncDownload (URL url, - std::function completionCallback, - std::function progressCallback = nullptr, - String extraHeaders = {}); - - /** Cancels all downloads */ - void cancelAllDownloads(); - - /** Cancels a download with a given id */ - void cancelDownload (int downloadId); - - //============================================================================== - DownloadResult blockingDownload (String url, String postData, String extraHeaders = {}); - - DownloadResult blockingDownload (URL url, String extraHeaders = {}); - -private: - //============================================================================== - /** Manages a download on a background thread */ - struct Download : public Thread - { - Download (DownloadManager& o) : Thread ("DownloadManager::Download"), owner (o) {} - ~Download() override; - - void run() override; - bool tryDownload(); - void updateProgress (int64 current, int64 total, bool ); - - //============================================================================== - DownloadResult result; - std::function completionCallback; - std::function progressCallback; - - std::unique_ptr is; - - DownloadManager& owner; - - String headers; - bool started = false, async = true; - uint32 lastProgress = 0; - int64 lastBytesSent = 0; - - //============================================================================== - JUCE_DECLARE_WEAK_REFERENCEABLE (Download) - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Download) - }; - - void downloadFinished (Download*); - void triggerNextDownload(); - - //============================================================================== - int nextId = 0; - int connectTimeout = 30 * 1000; - int shutdownTimeout = 30 * 1000; - int retryLimit = 0, priority = 5, downloadIntervalMS = 1000, downloadBlockSize = 128 * 1000; - - double retryDelay = 0.0; - int runningDownloads = 0, maxDownloads = 100; - OwnedArray downloads; - std::function queueFinishedCallback; - bool gzipDeflate = true; - juce::Atomic pause; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DownloadManager) -}; diff --git a/Modules/gin/utilities/easing.h b/Modules/gin/utilities/easing.h deleted file mode 100755 index c0114a2..0000000 --- a/Modules/gin/utilities/easing.h +++ /dev/null @@ -1,289 +0,0 @@ -// Easing functions based on AHEasing -// Converted to template functions for Gin -// -// Copyright (c) 2011, Auerhaus Development, LLC -// -// This program is free software. It comes without any warranty, to -// the extent permitted by applicable law. You can redistribute it -// and/or modify it under the terms of the Do What The Fuck You Want -// To Public License, Version 2, as published by Sam Hocevar. See -// http://sam.zoy.org/wtfpl/COPYING for more details. - -// Modeled after the line y = x -template -T easeLinear (T p) -{ - return p; -} - -// Modeled after the parabola y = x^2 -template -T easeQuadraticIn (T p) -{ - return p * p; -} - -// Modeled after the parabola y = -x^2 + 2x -template -T easeQuadraticOut (T p) -{ - return -(p * (p - 2)); -} - -// Modeled after the piecewise quadratic -// y = (1/2)((2x)^2) ; [0, 0.5) -// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] -template -T easeQuadraticInOut (T p) -{ - if (p < 0.5) - return 2 * p * p; - else - return (-2 * p * p) + (4 * p) - 1; -} - -// Modeled after the cubic y = x^3 -template -T easeCubicIn (T p) -{ - return p * p * p; -} - -// Modeled after the cubic y = (x - 1)^3 + 1 -template -T easeCubicOut (T p) -{ - T f = (p - 1); - return f * f * f + 1; -} - -// Modeled after the piecewise cubic -// y = (1/2)((2x)^3) ; [0, 0.5) -// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] -template -T easeCubicInOut (T p) -{ - if (p < 0.5) - return 4 * p * p * p; - - T f = ((2 * p) - 2); - return 0.5 * f * f * f + 1; -} - -// Modeled after the quartic x^4 -template -T easeQuarticIn (T p) -{ - return p * p * p * p; -} - -// Modeled after the quartic y = 1 - (x - 1)^4 -template -T easeQuarticOut (T p) -{ - T f = (p - 1); - return f * f * f * (1 - p) + 1; -} - -// Modeled after the piecewise quartic -// y = (1/2)((2x)^4) ; [0, 0.5) -// y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] -template -T easeQuarticInOut (T p) -{ - if (p < 0.5) - return 8 * p * p * p * p; - - T f = (p - 1); - return -8 * f * f * f * f + 1; -} - -// Modeled after the quintic y = x^5 -template -T easeQuinticIn (T p) -{ - return p * p * p * p * p; -} - -// Modeled after the quintic y = (x - 1)^5 + 1 -template -T easeQuinticOut (T p) -{ - T f = (p - 1); - return f * f * f * f * f + 1; -} - -// Modeled after the piecewise quintic -// y = (1/2)((2x)^5) ; [0, 0.5) -// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] -template -T easeQuinticInOut (T p) -{ - if (p < 0.5) - return 16 * p * p * p * p * p; - - T f = ((2 * p) - 2); - return 0.5 * f * f * f * f * f + 1; -} - -// Modeled after quarter-cycle of sine wave -template -T easeSineIn (T p) -{ - return std::sin ((p - 1) * (MathConstants::pi / 2)) + 1; -} - -// Modeled after quarter-cycle of sine wave (different phase) -template -T easeSineOut (T p) -{ - return std::sin (p * MathConstants::pi / 2); -} - -// Modeled after half sine wave -template -T easeSineInOut (T p) -{ - return T (0.5) * (1 - std::cos (p * MathConstants::pi)); -} - -// Modeled after shifted quadrant IV of unit circle -template -T easeCircularIn (T p) -{ - return 1 - std::sqrt (1 - (p * p)); -} - -// Modeled after shifted quadrant II of unit circle -template -T easeCircularOut (T p) -{ - return std::sqrt ((2 - p) * p); -} - -// Modeled after the piecewise circular function -// y = (1/2)(1 - sqrt(1 - 4x^2)) ; [0, 0.5) -// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] -template -T easeCircularInOut (T p) -{ - if (p < 0.5) - return 0.5 * (1 - std::sqrt (1 - 4 * (p * p))); - else - return 0.5 * (std::sqrt (-((2 * p) - 3) * ((2 * p) - 1)) + 1); -} - -// Modeled after the exponential function y = 2^(10(x - 1)) -template -T easeExponentialIn (T p) -{ - return (p == 0.0) ? p : std::pow (2, 10 * (p - 1)); -} - -// Modeled after the exponential function y = -2^(-10x) + 1 -template -T easeExponentialOut (T p) -{ - return (p == 1.0) ? p : 1 - std::pow (2, -10 * p); -} - -// Modeled after the piecewise exponential -// y = (1/2)2^(10(2x - 1)) ; [0,0.5) -// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] -template -T easeExponentialInOut (T p) -{ - if (p == 0.0 || p == 1.0) return p; - - if (p < 0.5) - return 0.5 * std::pow (2, (20 * p) - 10); - else - return -0.5 * std::pow (2, (-20 * p) + 10) + 1; -} - -// Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1)) -template -T easeElasticIn (T p) -{ - return std::sin (13 * (MathConstants::pi / 2) * p) * std::pow (2, 10 * (p - 1)); -} - -// Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1 -template -T easeElasticOut (T p) -{ - return std::sin (-13 * (MathConstants::pi / 2) * (p + 1)) * std::pow (2, -10 * p) + 1; -} - -// Modeled after the piecewise exponentially-damped sine wave: -// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1)) ; [0,0.5) -// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1] -template -T easeElasticInOut (T p) -{ - if (p < 0.5) - return 0.5 * std::sin (13 * (MathConstants::pi / 2) * (2 * p)) * std::pow (2, 10 * ((2 * p) - 1)); - else - return 0.5 * (std::sin (-13 * (MathConstants::pi / 2) * ((2 * p - 1) + 1)) * std::pow (2, -10 * (2 * p - 1)) + 2); -} - -// Modeled after the overshooting cubic y = x^3-x*sin(x*pi) -template -T easeBackIn (T p) -{ - return p * p * p - p * std::sin (p * MathConstants::pi); -} - -// Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) -template -T easeBackOut (T p) -{ - T f = (1 - p); - return 1 - (f * f * f - f * std::sin (f * MathConstants::pi)); -} - -// Modeled after the piecewise overshooting cubic function: -// y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5) -// y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1] -template -T easeBackInOut (T p) -{ - if (p < 0.5) - { - T f = 2 * p; - return 0.5 * (f * f * f - f * std::sin (f * MathConstants::pi)); - } - else - { - T f = (1 - (2*p - 1)); - return 0.5 * (1 - (f * f * f - f * std::sin (f * MathConstants::pi))) + 0.5; - } -} - -template -T easeBounceIn (T p) -{ - return 1 - easeBounceOut (1 - p); -} - -template -T easeBounceOut (T p) -{ - if (p < 4/11.0) - return (121 * p * p) / 16.0; - else if (p < 8/11.0) - return (363/40.0 * p * p) - (99/10.0 * p) + 17/5.0; - else if (p < 9/10.0) - return (4356/361.0 * p * p) - (35442/1805.0 * p) + 16061/1805.0; - else - return (54/5.0 * p * p) - (513/25.0 * p) + 268/25.0; -} - -template -T easeBounceInOut (T p) -{ - if (p < 0.5) - return 0.5 * easeBounceEaseIn (p * 2); - else - return 0.5 * easeBounceEaseOut (p * 2 - 1) + 0.5; -} diff --git a/Modules/gin/utilities/elevatedfilecopy.cpp b/Modules/gin/utilities/elevatedfilecopy.cpp deleted file mode 100755 index 618526e..0000000 --- a/Modules/gin/utilities/elevatedfilecopy.cpp +++ /dev/null @@ -1,354 +0,0 @@ - /*============================================================================== - - Copyright 2019 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#if JUCE_MAC - -ElevatedFileCopy::Result runWithPermissions (String cmd, StringArray params) -{ - OSStatus err = noErr; - auto path = cmd.toRawUTF8(); - - Array rawParams; - for (auto& s : params) - rawParams.add (s.toRawUTF8()); - rawParams.add (nullptr); - - AuthorizationRef authorizationRef; - AuthorizationItem item = { kAuthorizationRightExecute, strlen (path), &path, 0 }; - AuthorizationRights rights = { 1, &item }; - AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights; - - err = AuthorizationCreate (nullptr, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef); - if (err != errAuthorizationSuccess) - return ElevatedFileCopy::failed; - - err = AuthorizationCopyRights (authorizationRef, &rights, kAuthorizationEmptyEnvironment, flags, nullptr); - if (err == errAuthorizationCanceled) - return ElevatedFileCopy::cancelled; - - if (err != errAuthorizationSuccess) - return ElevatedFileCopy::nopermissions; - - FILE* outputFile = nullptr; - - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wdeprecated-declarations" - err = AuthorizationExecuteWithPrivileges (authorizationRef, path, kAuthorizationFlagDefaults, (char* const*)rawParams.getRawDataPointer(), &outputFile); - #pragma clang diagnostic pop - - if (err == noErr) - { - auto processIdentifier = fcntl (fileno (outputFile), F_GETOWN, 0); - - AuthorizationFree (authorizationRef, kAuthorizationFlagDefaults); - - int status; - pid_t pid = 0; - - while ((pid = waitpid (processIdentifier, &status, WNOHANG)) == 0) - Thread::sleep (10); - - fclose (outputFile); - - auto terminationStatus = WEXITSTATUS (status); - if (terminationStatus == 0) - return ElevatedFileCopy::success; - - return ElevatedFileCopy::failed; - } - return ElevatedFileCopy::nopermissions; -} - -static String escape (const String& in) -{ - return in.replace (" ", "\\ "); -} - -ElevatedFileCopy::Result ElevatedFileCopy::runScriptWithAdminAccess (File script, bool launchSelf) -{ - ignoreUnused (launchSelf); - runWithPermissions ("/bin/sh", { script.getFullPathName() }); - return success; -} - -File ElevatedFileCopy::createScript (const Array& toDelete, - const Array& dirsThatNeedAdminAccess, - const Array& filesThatNeedAdminAccess) -{ - auto script = File::getSpecialLocation (File::tempDirectory).getNonexistentChildFile ("copy", ".sh", false); - - String scriptText; - - scriptText += "#!/bin/sh\n"; - - Array dirs; - - for (auto f : toDelete) - scriptText += "rm -Rf " + escape (f.getFullPathName()) + "\n"; - - for (auto f : dirsThatNeedAdminAccess) - dirs.add (f); - - for (auto f : filesThatNeedAdminAccess) - if (! f.dst.getParentDirectory().isDirectory()) - dirs.addIfNotAlreadyThere (f.dst.getParentDirectory()); - - for (auto d : dirs) - scriptText += "mkdir -p " + escape (d.getFullPathName()) + "\n"; - - for (auto d : dirsThatNeedAdminAccess) - scriptText += "chmod 777 " + escape (d.getFullPathName()) + "\n"; - - scriptText += "\n"; - - for (auto f : filesThatNeedAdminAccess) - scriptText += "cp -p " + escape (f.src.getFullPathName()) + " " + escape (f.dst.getFullPathName()) + " || exit 1\n"; - - script.replaceWithText (scriptText, false, false, "\n"); - - return script; -} - -#endif - -#if JUCE_WINDOWS -static std::wstring toWideString (const std::string& s) -{ - int len = MultiByteToWideChar (CP_UTF8, 0, s.c_str(), (int)s.length() + 1, 0, 0); - - wchar_t* buffer = new wchar_t[len]; - MultiByteToWideChar (CP_UTF8, 0, s.c_str(), (int)s.length() + 1, buffer, len); - - std::wstring res (buffer); - delete[] buffer; - - return res; -} - -ElevatedFileCopy::Result ElevatedFileCopy::runScriptWithAdminAccess (File script, bool launchSelf) -{ - String app; - String params; - - if (launchSelf) - { - app = File::getSpecialLocation (File::currentExecutableFile).getFullPathName(); - params = "--elevatedfilecopy \"" + script.getFullPathName() + "\""; - } - else - { - app = "cmd.exe"; - params = "/c \"" + script.getFullPathName() + "\""; - } - - auto wideParams = toWideString (params.toRawUTF8()); - auto wideApp = toWideString (app.toRawUTF8()); - - SHELLEXECUTEINFOW info; - memset (&info, 0, sizeof (info)); - info.cbSize = sizeof (info); - info.fMask = SEE_MASK_NOCLOSEPROCESS; - info.lpVerb = L"runas"; - info.lpFile = wideApp.c_str(); - info.lpParameters = wideParams.c_str(); - info.nShow = SW_HIDE; - - if (ShellExecuteExW (&info)) - { - WaitForSingleObject (info.hProcess, INFINITE); - - DWORD exitCode = 0; - GetExitCodeProcess (info.hProcess, &exitCode); - CloseHandle (info.hProcess); - - return exitCode == 0 ? success : failed; - } - else - { - auto err = GetLastError(); - if (err == ERROR_CANCELLED) - return cancelled; - - return nopermissions; - } -} - -File ElevatedFileCopy::createScript (const Array& toDelete, - const Array& dirsThatNeedAdminAccess, - const Array& filesThatNeedAdminAccess) -{ - auto script = File::getSpecialLocation (File::tempDirectory).getNonexistentChildFile ("copy", ".bat", false); - - String scriptText; - - Array dirs; - - for (auto f : toDelete) - { - if (f.isDirectory()) - scriptText += "rmdir /s /q " + f.getFullPathName().quoted() + "\r\n"; - else if (f.existsAsFile()) - scriptText += "del /f " + f.getFullPathName().quoted() + "\r\n"; - } - - for (auto f : dirsThatNeedAdminAccess) - dirs.add (f); - - for (auto f : filesThatNeedAdminAccess) - if (! f.dst.getParentDirectory().isDirectory()) - dirs.addIfNotAlreadyThere (f.dst.getParentDirectory()); - - for (auto d : dirs) - scriptText += "if not exist \"" + d.getFullPathName() + "\" mkdir " + d.getFullPathName().quoted() + "\r\n"; - - scriptText += "\r\n"; - - for (auto f : filesThatNeedAdminAccess) - { - scriptText += "copy " + f.src.getFullPathName().quoted() + " " + f.dst.getFullPathName().quoted() + "\r\n"; - scriptText += "if %errorlevel% neq 0 goto :error\r\n"; - } - - scriptText += "exit /b 0\r\n"; - scriptText += ":error\r\n"; - scriptText += "exit /b 1\r\n"; - - script.replaceWithText (scriptText); - - return script; -} -#endif - -#if defined JUCE_MAC || defined JUCE_WINDOWS - -void ElevatedFileCopy::createDir (const File& dir) -{ - dirsToCreate.add (dir); -} - -void ElevatedFileCopy::copyFile (const File& src, const File& dst) -{ - filesToCopy.add ({ src, dst }); -} - -void ElevatedFileCopy::deleteFile (const File& f) -{ - filesToDelete.add (f); -} - -ElevatedFileCopy::Result ElevatedFileCopy::execute (bool launchSelf) -{ - Array filesToDeleteThatNeedAdminAccess; - Array dirsThatNeedAdminAccess; - Array filesThatNeedAdminAccess; - - for (auto f : filesToDelete) - { - if (f.existsAsFile()) - { - if (! f.deleteFile()) - filesToDeleteThatNeedAdminAccess.add (f); - } - else if (f.isDirectory()) - { - if (! f.deleteRecursively()) - filesToDeleteThatNeedAdminAccess.add (f); - } - } - - for (auto f : dirsToCreate) - { - if (! f.isDirectory()) - f.createDirectory(); - - bool ok = f.isDirectory(); - - if (! ok) - dirsThatNeedAdminAccess.add (f); - } - - for (auto f : filesToCopy) - { - bool ok = false; - - auto dstDir = f.dst.getParentDirectory(); - if (! dstDir.isDirectory()) - dstDir.createDirectory(); - - if (dstDir.isDirectory()) - ok = f.src.copyFileTo (f.dst); - - if (! ok) - filesThatNeedAdminAccess.add (f); - } - - if (filesToDeleteThatNeedAdminAccess.size() > 0 || dirsThatNeedAdminAccess.size() > 0 || filesThatNeedAdminAccess.size() > 0) - { - File script = createScript (filesToDeleteThatNeedAdminAccess, dirsThatNeedAdminAccess, filesThatNeedAdminAccess); - auto res = runScriptWithAdminAccess (script, launchSelf); - script.deleteFile(); - - return res; - } - - return success; -} - -bool ElevatedFileCopy::processCommandLine (juce::String commandLine) -{ - #if JUCE_WINDOWS - if (commandLine.contains ("--elevatedfilecopy")) - { - String script = commandLine.fromFirstOccurrenceOf ("--elevatedfilecopy \"", false, false).upToFirstOccurrenceOf ("\"", false, false); - - if (File (script).existsAsFile()) - { - String params = "/c \"" + script + "\""; - auto wideParams = toWideString (params.toRawUTF8()); - - SHELLEXECUTEINFOW info; - memset (&info, 0, sizeof (info)); - info.cbSize = sizeof (info); - info.fMask = SEE_MASK_NOCLOSEPROCESS; - info.lpVerb = L"runas"; - info.lpFile = L"cmd.exe"; - info.lpParameters = wideParams.c_str(); - info.nShow = SW_HIDE; - - if (ShellExecuteExW (&info)) - { - WaitForSingleObject (info.hProcess, INFINITE); - - DWORD exitCode = 0; - GetExitCodeProcess (info.hProcess, &exitCode); - CloseHandle (info.hProcess); - - if (auto inst = JUCEApplication::getInstance()) - inst->setApplicationReturnValue (exitCode); - } - else - { - if (auto inst = JUCEApplication::getInstance()) - inst->setApplicationReturnValue (1); - } - } - - JUCEApplication::quit(); - return true; - } - #else - ignoreUnused (commandLine); - #endif - return false; -} - -void ElevatedFileCopy::clear() -{ - filesToCopy.clear(); -} - -#endif diff --git a/Modules/gin/utilities/elevatedfilecopy.h b/Modules/gin/utilities/elevatedfilecopy.h deleted file mode 100755 index d7e85e4..0000000 --- a/Modules/gin/utilities/elevatedfilecopy.h +++ /dev/null @@ -1,82 +0,0 @@ -/*============================================================================== - - Copyright 2019 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -// TODO: no implementation for Linux yet - -#if defined JUCE_MAC || defined JUCE_WINDOWS - -/** Copies files, creating folders where required - requesting admin access only if required - */ -class ElevatedFileCopy -{ -public: - enum Result - { - success, - failed, - cancelled, - nopermissions - }; - - /** Add a directory to create */ - void createDir (const File& dir); - - /** Add a file to copy. src and dst must be complete file names, - neither can be a directory */ - void copyFile (const File& src, const File& dst); - - /** Delete a file or directory */ - void deleteFile (const File& f); - - /** Perform the copy - - If launchSelf is false, then on Windows cmd.exe will be executed - with admin permissions to copy the files. This looks odd to the user - since Windows Command Processor will ask for permissions to make changes - rather than your app. Pass true to make your app get launched with admin - permissions instead. In this case, you must call processCommandLine from - yours apps initialise instead, and if it returns true, return from initialise - asap and your app will quit as it's just a temporary process. - */ - Result execute (bool launchSelf = false); - - /** Clear all files to be copied */ - void clear(); - - /** Call from JUCEApplication::initialise() and abort the initialise process - if returns true */ - static bool processCommandLine (juce::String commandLine); - - /** Run a script as root. See execute for the meaning of launch self */ - static Result runScriptWithAdminAccess (File script, bool launchSelf); - -private: - struct FileItem - { - FileItem (File s = {}, File d = {}) - : src (s), dst (d) - {} - - File src; - File dst; - }; - - File createScript (const Array& toDelete, - const Array& dirsThatNeedAdminAccess, - const Array& filesThatNeedAdminAccess); - - Array filesToCopy; - Array dirsToCreate; - Array filesToDelete; - - JUCE_LEAK_DETECTOR (ElevatedFileCopy) -}; - -#endif diff --git a/Modules/gin/utilities/equationparser.cpp b/Modules/gin/utilities/equationparser.cpp deleted file mode 100755 index d53ecfd..0000000 --- a/Modules/gin/utilities/equationparser.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/*============================================================================== - -Copyright 2018 by Roland Rabien -For more information visit www.rabiensoftware.com - -==============================================================================*/ - -#if __clang__ - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Wswitch-enum" -#endif - -#include "../3rdparty/muParser/muParser.h" - -#if __clang__ - #pragma clang diagnostic pop -#endif - -namespace gin { - -//============================================================================== -class EquationParser::Callback0 : public EquationParser::Callback -{ -public: - Callback0 (std::function f) : fun (f) {} - std::function fun; -}; -class EquationParser::Callback1 : public EquationParser::Callback -{ -public: - Callback1 (std::function f) : fun (f) {} - std::function fun; -}; -class EquationParser::Callback2 : public EquationParser::Callback -{ -public: - Callback2 (std::function f) : fun (f) {} - std::function fun; -}; -class EquationParser::Callback3 : public EquationParser::Callback -{ -public: - Callback3 (std::function f) : fun (f) {} - std::function fun; -}; -class EquationParser::Callback4 : public EquationParser::Callback -{ -public: - Callback4 (std::function f) : fun (f) {} - std::function fun; -}; - -//============================================================================== -double modFunc(mu::SParam, double a, double b) -{ - return std::fmod (a, b); -} - -//============================================================================== -class EquationParser::EquationParserImpl -{ -public: - mu::Parser parser; -}; - -//============================================================================== -EquationParser::EquationParser() -{ - impl = std::make_unique(); -} - -EquationParser::EquationParser (juce::String equation) -{ - try - { - impl = std::make_unique(); - impl->parser.SetExpr (equation.toRawUTF8()); - - impl->parser.DefineOprt ("%", modFunc, mu::prMUL_DIV, mu::oaLEFT, false); - } - catch (...) - { - } -} - -EquationParser::~EquationParser() -{ - -} - -void EquationParser::setEquation (juce::String equation) -{ - try - { - impl->parser.SetExpr (equation.toRawUTF8()); - } - catch (mu::Parser::exception_type& e) - { - errorMessage = String (e.GetMsg()); - } -} - -void EquationParser::addVariable (juce::String name, double* value) -{ - try - { - impl->parser.DefineVar (name.toRawUTF8(), value); - } - catch (...) - { - } -} - -void EquationParser::addConstant (juce::String name, double value) -{ - try - { - impl->parser.DefineConst (name.toRawUTF8(), value); - } - catch (...) - { - } -} - -void EquationParser::addFunction (juce::String name, std::function fun) -{ - try - { - auto cb = new Callback0 (fun); - impl->parser.DefineFun (name.toRawUTF8(), [] (mu::SParam s) - { - auto c = (Callback0*)s.param; - return c->fun (s.id); - }, cb, false); - callbacks.add (cb); - } - catch (...) - { - } -} - -void EquationParser::addFunction (juce::String name, std::function fun) -{ - try - { - auto cb = new Callback1 (fun); - impl->parser.DefineFun (name.toRawUTF8(), [] (mu::SParam s, double p1) - { - auto c = (Callback1*)s.param; - return c->fun (s.id, p1); - }, cb, false); - callbacks.add (cb); - } - catch (...) - { - } -} - -void EquationParser::addFunction (juce::String name, std::function fun) -{ - try - { - auto cb = new Callback2 (fun); - impl->parser.DefineFun (name.toRawUTF8(), [] (mu::SParam s, double p1, double p2) - { - auto c = (Callback2*)s.param; - return c->fun (s.id, p1, p2); - }, cb, false); - callbacks.add (cb); - } - catch (...) - { - } -} - -void EquationParser::addFunction (juce::String name, std::function fun) -{ - try - { - auto cb = new Callback3 (fun); - impl->parser.DefineFun (name.toRawUTF8(), [] (mu::SParam s, double p1, double p2, double p3) - { - auto c = (Callback3*)s.param; - return c->fun (s.id, p1, p2, p3); - }, cb, false); - callbacks.add (cb); - } - catch (...) - { - } -} - -void EquationParser::addFunction (juce::String name, std::function fun) -{ - try - { - auto cb = new Callback4 (fun); - impl->parser.DefineFun (name.toRawUTF8(), [] (mu::SParam s, double p1, double p2, double p3, double p4) - { - auto c = (Callback4*)s.param; - return c->fun (s.id, p1, p2, p3, p4); - }, cb, false); - callbacks.add (cb); - } - catch (...) - { - } -} - -double EquationParser::evaluate() -{ - try - { - return impl->parser.Eval(); - } - catch (mu::Parser::exception_type& e) - { - errorMessage = String (e.GetMsg()); - } - return 0; -} - -bool EquationParser::hasError() -{ - return errorMessage.isNotEmpty(); -} - -juce::String EquationParser::getError() -{ - return errorMessage; -} - -} diff --git a/Modules/gin/utilities/equationparser.h b/Modules/gin/utilities/equationparser.h deleted file mode 100755 index 08fed93..0000000 --- a/Modules/gin/utilities/equationparser.h +++ /dev/null @@ -1,52 +0,0 @@ -/*============================================================================== - -Copyright 2018 by Roland Rabien -For more information visit www.rabiensoftware.com - -==============================================================================*/ - -#pragma once - -class EquationParser -{ -public: - EquationParser(); - EquationParser (juce::String equation); - ~EquationParser(); - - void setEquation (juce::String equation); - void addVariable (juce::String name, double* value); - - void addConstant (juce::String name, double value); - - void addFunction (juce::String name, std::function fun); - void addFunction (juce::String name, std::function fun); - void addFunction (juce::String name, std::function fun); - void addFunction (juce::String name, std::function fun); - void addFunction (juce::String name, std::function fun); - - double evaluate(); - - bool hasError(); - juce::String getError(); - -private: - class Callback - { - public: - virtual ~Callback() = default; - }; - class Callback0; - class Callback1; - class Callback2; - class Callback3; - class Callback4; - - OwnedArray callbacks; - - class EquationParserImpl; - std::unique_ptr impl; - juce::String errorMessage; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (EquationParser) -}; diff --git a/Modules/gin/utilities/filesystemwatcher.cpp b/Modules/gin/utilities/filesystemwatcher.cpp deleted file mode 100755 index bf02b95..0000000 --- a/Modules/gin/utilities/filesystemwatcher.cpp +++ /dev/null @@ -1,329 +0,0 @@ -/*============================================================================== - -Copyright 2018 by Roland Rabien -For more information visit www.rabiensoftware.com - -==============================================================================*/ - -//============================================================================== -#if JUCE_MAC -class FileSystemWatcher::Impl -{ -public: - Impl (FileSystemWatcher& o, File f) : owner (o), folder (f) - { - NSString* newPath = [NSString stringWithUTF8String:folder.getFullPathName().toRawUTF8()]; - - paths = [[NSArray arrayWithObject:newPath] retain]; - context.version = 0L; - context.info = this; - context.retain = nil; - context.release = nil; - context.copyDescription = nil; - - stream = FSEventStreamCreate (kCFAllocatorDefault, callback, &context, (CFArrayRef)paths, kFSEventStreamEventIdSinceNow, 0.05, - kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents); - if (stream) - { - FSEventStreamScheduleWithRunLoop (stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - FSEventStreamStart (stream); - } - - } - - ~Impl() - { - if (stream) - { - FSEventStreamStop (stream); - FSEventStreamUnscheduleFromRunLoop (stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - FSEventStreamInvalidate (stream); - FSEventStreamRelease (stream); - } - } - - static void callback (ConstFSEventStreamRef streamRef, void* clientCallBackInfo, size_t numEvents, void* eventPaths, - const FSEventStreamEventFlags* eventFlags, const FSEventStreamEventId* eventIds) - { - ignoreUnused (streamRef, numEvents, eventIds, eventPaths, eventFlags); - - Impl* impl = (Impl*)clientCallBackInfo; - impl->owner.folderChanged (impl->folder); - - char** files = (char**)eventPaths; - - for (int i = 0; i < int (numEvents); i++) - { - char* file = files[i]; - FSEventStreamEventFlags evt = eventFlags[i]; - - File path = String::fromUTF8 (file); - if (evt & kFSEventStreamEventFlagItemModified) - impl->owner.fileChanged (path, FileSystemEvent::fileUpdated); - else if (evt & kFSEventStreamEventFlagItemRemoved) - impl->owner.fileChanged (path, FileSystemEvent::fileDeleted); - else if (evt & kFSEventStreamEventFlagItemRenamed) - impl->owner.fileChanged (path, path.exists() ? FileSystemEvent::fileRenamedNewName : FileSystemEvent::fileRenamedOldName); - else if (evt & kFSEventStreamEventFlagItemCreated) - impl->owner.fileChanged (path, FileSystemEvent::fileCreated); - } - } - - FileSystemWatcher& owner; - const File folder; - - NSArray* paths; - FSEventStreamRef stream; - struct FSEventStreamContext context; -}; -#endif - -//============================================================================== -#ifdef JUCE_LINUX -#define BUF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1)) - -class FileSystemWatcher::Impl : public Thread, - private AsyncUpdater -{ -public: - Impl (FileSystemWatcher& o, File f) - : Thread ("FileSystemWatcher::Impl"), owner (o), folder (f) - { - fd = inotify_init(); - - wd = inotify_add_watch (fd, - folder.getFullPathName().toRawUTF8(), - IN_ATTRIB | IN_CREATE | IN_DELETE | IN_DELETE_SELF | - IN_MODIFY | IN_MOVE_SELF | IN_MOVED_TO | IN_MOVED_FROM); - - startThread(); - } - - ~Impl() - { - signalThreadShouldExit(); - inotify_rm_watch (fd, wd); - close (fd); - - waitForThreadToExit (1000); - } - - void run() override - { - char buf[BUF_LEN]; - - while (true) - { - int numRead = read (fd, buf, BUF_LEN); - - if (numRead <= 0 || threadShouldExit()) - break; - - triggerAsyncUpdate(); - } - } - - void handleAsyncUpdate() override - { - owner.folderChanged (folder); - } - - FileSystemWatcher& owner; - File folder; - - int fd; - int wd; -}; -#endif - -//============================================================================== -#ifdef JUCE_WINDOWS -class FileSystemWatcher::Impl : private AsyncUpdater, - private Thread -{ -public: - struct Event - { - File file; - FileSystemEvent fsEvent; - - bool operator== (const Event& other) const - { - return file == other.file && fsEvent == other.fsEvent; - } - }; - - Impl (FileSystemWatcher& o, File f) - : Thread ("FileSystemWatcher::Impl"), owner (o), folder (f) - { - WCHAR path[_MAX_PATH] = {0}; - wcsncpy (path, folder.getFullPathName().toWideCharPointer(), _MAX_PATH - 1); - - folderHandle = CreateFileW (path, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - - - if (folderHandle != INVALID_HANDLE_VALUE) - startThread(); - } - - ~Impl() - { - if (isThreadRunning()) - { - signalThreadShouldExit(); - - CancelIoEx (folderHandle, nullptr); - - stopThread (1000); - } - - CloseHandle (folderHandle); - } - - void run() override - { - const int heapSize = 16 * 1024; - uint8 buffer[heapSize]; - - DWORD bytesOut = 0; - - while (! threadShouldExit()) - { - memset (buffer, 0, heapSize); - BOOL success = ReadDirectoryChangesW (folderHandle, buffer, heapSize, true, - FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION, - &bytesOut, nullptr, nullptr); - - if (success && bytesOut > 0) - { - ScopedLock sl (lock); - - uint8* rawData = buffer; - while (true) - { - FILE_NOTIFY_INFORMATION* fni = (FILE_NOTIFY_INFORMATION*)rawData; - - Event e; - e.file = folder.getChildFile (String (fni->FileName, fni->FileNameLength / sizeof(wchar_t))); - - switch (fni->Action) - { - case FILE_ACTION_ADDED: - e.fsEvent = fileCreated; - break; - case FILE_ACTION_RENAMED_NEW_NAME: - e.fsEvent = fileRenamedNewName; - break; - case FILE_ACTION_MODIFIED: - e.fsEvent = fileUpdated; - break; - case FILE_ACTION_REMOVED: - e.fsEvent = fileDeleted; - break; - case FILE_ACTION_RENAMED_OLD_NAME: - e.fsEvent = fileRenamedOldName; - break; - } - - bool duplicateEvent = false; - for (auto existing : events) - { - if (e == existing) - { - duplicateEvent = true; - break; - } - } - - if (! duplicateEvent) - events.add (e); - - if (fni->NextEntryOffset > 0) - rawData += fni->NextEntryOffset; - else - break; - } - - if (events.size() > 0) - triggerAsyncUpdate(); - } - } - } - - void handleAsyncUpdate() override - { - ScopedLock sl (lock); - - owner.folderChanged (folder); - - for (auto e : events) - owner.fileChanged (e.file, e.fsEvent); - - events.clear(); - } - - FileSystemWatcher& owner; - const File folder; - - CriticalSection lock; - Array events; - - HANDLE folderHandle; -}; -#endif - -#if defined JUCE_MAC || defined JUCE_WINDOWS || defined JUCE_LINUX -FileSystemWatcher::FileSystemWatcher() -{ -} - -FileSystemWatcher::~FileSystemWatcher() -{ -} - -void FileSystemWatcher::addFolder (const File& folder) -{ - // You can only listen to folders that exist - jassert (folder.isDirectory()); - - watched.add (new Impl (*this, folder)); -} - -void FileSystemWatcher::removeFolder (const File& folder) -{ - for (int i = watched.size(); --i >= 0;) - { - if (watched[i]->folder == folder) - { - watched.remove (i); - break; - } - } -} - -void FileSystemWatcher::removeAllFolders() -{ - watched.clear(); -} - -void FileSystemWatcher::addListener (Listener* newListener) -{ - listeners.add (newListener); -} - -void FileSystemWatcher::removeListener (Listener* listener) -{ - listeners.remove (listener); -} - -void FileSystemWatcher::folderChanged (const File& folder) -{ - listeners.call (&FileSystemWatcher::Listener::folderChanged, folder); -} - -void FileSystemWatcher::fileChanged (const File& file, FileSystemEvent fsEvent) -{ - listeners.call (&FileSystemWatcher::Listener::fileChanged, file, fsEvent); -} -#endif diff --git a/Modules/gin/utilities/filesystemwatcher.h b/Modules/gin/utilities/filesystemwatcher.h deleted file mode 100755 index 15e9622..0000000 --- a/Modules/gin/utilities/filesystemwatcher.h +++ /dev/null @@ -1,93 +0,0 @@ -/*============================================================================== - -Copyright 2018 by Roland Rabien -For more information visit www.rabiensoftware.com - -==============================================================================*/ - -#pragma once - -#if defined JUCE_MAC || defined JUCE_WINDOWS || defined JUCE_LINUX - -/** - - Watches a folder in the file system for changes. - - Listener callbcks will be called every time a file is - created, modified, deleted or renamed in the watched - folder. - - FileSystemWatcher will also recursively watch all subfolders on - macOS and windows and will not on Linux. - - */ -class FileSystemWatcher -{ -public: - //============================================================================== - FileSystemWatcher(); - ~FileSystemWatcher(); - - //============================================================================== - /** Adds a folder to be watched */ - void addFolder (const File& folder); - /** Removes a folder from being watched */ - void removeFolder (const File& folder); - /** Removes all folders from being watched */ - void removeAllFolders(); - - /** A set of events that can happen to a file. - When a file is renamed it will appear as the - original filename being deleted and the new - filename being created - */ - enum FileSystemEvent - { - fileCreated, - fileDeleted, - fileUpdated, - fileRenamedOldName, - fileRenamedNewName - }; - - //============================================================================== - /** Receives callbacks from the FileSystemWatcher when a file changes */ - class Listener - { - public: - virtual ~Listener() = default; - - /* Called when any file in the listened to folder changes with the name of - the folder that has changed. For example, use this for a file browser that - needs to refresh any time a file changes */ - virtual void folderChanged (const File) {} - - /* Called for each file that has changed and how it has changed. Use this callback - if you need to reload a file when it's contents change */ - virtual void fileChanged (const File, FileSystemEvent) {} - }; - - /** Registers a listener to be told when things happen to the text. - @see removeListener - */ - void addListener (Listener* newListener); - - /** Deregisters a listener. - @see addListener - */ - void removeListener (Listener* listener); - -private: - class Impl; - - void folderChanged (const File& folder); - void fileChanged (const File& file, FileSystemEvent fsEvent); - - ListenerList listeners; - - OwnedArray watched; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileSystemWatcher) -}; - -#endif diff --git a/Modules/gin/utilities/fileutilities.cpp b/Modules/gin/utilities/fileutilities.cpp deleted file mode 100755 index 86e0389..0000000 --- a/Modules/gin/utilities/fileutilities.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/*============================================================================== - - Copyright 2019 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -bool overwriteWithText (const juce::File& f, const juce::String& text, bool asUnicode, - bool writeUnicodeHeaderBytes, - const char* lineEndings) -{ - FileOutputStream out (f); - - if (out.failedToOpen()) - return false; - - out.setPosition (0); - bool ok = out.writeText (text, asUnicode, writeUnicodeHeaderBytes, lineEndings); - out.truncate(); - - return ok; -} - -bool overwriteWithData (const juce::File& f, const juce::MemoryBlock& data) -{ - return overwriteWithData (f, data.getData(), data.getSize()); -} - -bool overwriteWithData (const juce::File& f, const void* data, size_t size) -{ - FileOutputStream out (f); - - if (out.failedToOpen()) - return false; - - out.setPosition (0); - bool ok = true; - if (size > 0) - ok = out.write (data, size); - out.truncate(); - - return ok; -} diff --git a/Modules/gin/utilities/fileutilities.h b/Modules/gin/utilities/fileutilities.h deleted file mode 100755 index 465e9d4..0000000 --- a/Modules/gin/utilities/fileutilities.h +++ /dev/null @@ -1,23 +0,0 @@ -/*============================================================================== - - Copyright 2019 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -/* Replaces a file with text in one operation without creating a temp file - */ -bool overwriteWithText (const juce::File& f, const juce::String& text, - bool asUnicode = false, - bool writeUnicodeHeaderBytes = false, - const char* lineEndings = nullptr); - -/* Replaces a file with data in one operation without creating a temp file - */ -bool overwriteWithData (const juce::File& f, const juce::MemoryBlock& data); - -bool overwriteWithData (const juce::File& f, const void* data, size_t size); - - diff --git a/Modules/gin/utilities/integrator.cpp b/Modules/gin/utilities/integrator.cpp deleted file mode 100755 index 49a91f6..0000000 --- a/Modules/gin/utilities/integrator.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -void Integrator::clear() -{ - first = true; - curSum = 0; - oldX = 0; - oldY = 0; -} - -double Integrator::getIntegral() -{ - return curSum; -} - -void Integrator::addPoint (double x, double y) -{ - if (first) - { - first = false; - } - else - { - double curY = (oldY + y) / 2.0; - curSum += curY * (x - oldX); - } - oldX = x; - oldY = y; -} - -void Integrator::addPoint (juce::Point point) -{ - addPoint (point.getX(), point.getY()); -} - -void Integrator::addPoints (Array> points) -{ - for (auto point : points) - addPoint (point.getX(), point.getY()); -} diff --git a/Modules/gin/utilities/integrator.h b/Modules/gin/utilities/integrator.h deleted file mode 100755 index 6d24e49..0000000 --- a/Modules/gin/utilities/integrator.h +++ /dev/null @@ -1,31 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -/** Calculates the integral of a function defined by a series of points. Points - must be added in increasing x order */ -class Integrator -{ -public: - void clear(); - - double getIntegral(); - - void addPoint (double x, double y); - void addPoint (juce::Point point); - void addPoints (Array> points); - -private: - - bool first = true; - double oldX = 0; - double oldY = 0; - double curSum = 0; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Integrator) -}; diff --git a/Modules/gin/utilities/lagrange.h b/Modules/gin/utilities/lagrange.h deleted file mode 100755 index 9d3ac37..0000000 --- a/Modules/gin/utilities/lagrange.h +++ /dev/null @@ -1,70 +0,0 @@ -/*============================================================================== - - Copyright 2020 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -/** Lagrange interpolation is a simple way to obtain a smooth curve from a set of - discrete points. -*/ - -namespace Lagrange -{ - -template -T interpolate (const Array>& points, T x) -{ - T res = 0; - - const int num = points.size(); - for (int i = 0; i < num; i++) - { - T term = points[i].y; - for (int j = 0; j < num; j++) - { - if (i != j) - { - auto d = points[i].x - points[j].x; - if (d != 0) - term = term * (x - points[j].x ) / (d); - else - term = 0; - } - } - - res += term; - } - - return res; -} - -template -T interpolate (T xArr[], T yArr[], int num, T x) -{ - T res = 0; - - for (int i = 0; i < num; i++) - { - T term = yArr[i]; - for (int j = 0; j < num; j++) - { - if (i != j) - { - auto d = xArr[i] - xArr[j]; - if (d != 0) - term = term * (x - xArr[j] ) / d; - else - term = 0; - } - } - - res += term; - } - - return res; -} - -} diff --git a/Modules/gin/utilities/leastsquaresregression.cpp b/Modules/gin/utilities/leastsquaresregression.cpp deleted file mode 100755 index 9b555b0..0000000 --- a/Modules/gin/utilities/leastsquaresregression.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien, 2010 by 2010 by Alex Etchells - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -void LeastSquaresRegression::addPoint (double x, double y) -{ - pointArray.add ({x, y}); -} - -void LeastSquaresRegression::addPoint (juce::Point point) -{ - pointArray.add (point); -} - -void LeastSquaresRegression::addPoints (Array> points) -{ - pointArray.addArray (points); -} - -void LeastSquaresRegression::clear() -{ - pointArray.clear(); -} - -bool LeastSquaresRegression::enoughPoints() -{ - return pointArray.size() >= 3; -} - -Array LeastSquaresRegression::getTerms() -{ - //notation sjk to mean the sum of x_i^j*y_i^k. - double s40 = getSx4(); //sum of x^4 - double s30 = getSx3(); //sum of x^3 - double s20 = getSx2(); //sum of x^2 - double s10 = getSx(); //sum of x - double s00 = pointArray.size(); - //sum of x^0 * y^0 ie 1 * number of entries - - double s21 = getSx2y(); //sum of x^2*y - double s11 = getSxy(); //sum of x*y - double s01 = getSy(); //sum of y - - double a = (s21*(s20 * s00 - s10 * s10) - - s11*(s30 * s00 - s10 * s20) + - s01*(s30 * s10 - s20 * s20)) - / - (s40*(s20 * s00 - s10 * s10) - - s30*(s30 * s00 - s10 * s20) + - s20*(s30 * s10 - s20 * s20)); - - double b = (s40*(s11 * s00 - s01 * s10) - - s30*(s21 * s00 - s01 * s20) + - s20*(s21 * s10 - s11 * s20)) - / - (s40 * (s20 * s00 - s10 * s10) - - s30 * (s30 * s00 - s10 * s20) + - s20 * (s30 * s10 - s20 * s20)); - - double c = (s40*(s20 * s01 - s10 * s11) - - s30*(s30 * s01 - s10 * s21) + - s20*(s30 * s11 - s20 * s21)) - / - (s40 * (s20 * s00 - s10 * s10) - - s30 * (s30 * s00 - s10 * s20) + - s20 * (s30 * s10 - s20 * s20)); - - Array terms; - terms.add (a); - terms.add (b); - terms.add (c); - return terms; -} - -double LeastSquaresRegression::aTerm() -{ - //notation sjk to mean the sum of x_i^j*y_i^k. - double s40 = getSx4(); //sum of x^4 - double s30 = getSx3(); //sum of x^3 - double s20 = getSx2(); //sum of x^2 - double s10 = getSx(); //sum of x - double s00 = pointArray.size(); - //sum of x^0 * y^0 ie 1 * number of entries - - double s21 = getSx2y(); //sum of x^2*y - double s11 = getSxy(); //sum of x*y - double s01 = getSy(); //sum of y - - //a = Da/D - return (s21*(s20 * s00 - s10 * s10) - - s11*(s30 * s00 - s10 * s20) + - s01*(s30 * s10 - s20 * s20)) - / - (s40*(s20 * s00 - s10 * s10) - - s30*(s30 * s00 - s10 * s20) + - s20*(s30 * s10 - s20 * s20)); -} - -double LeastSquaresRegression::bTerm() -{ - //notation sjk to mean the sum of x_i^j*y_i^k. - double s40 = getSx4(); //sum of x^4 - double s30 = getSx3(); //sum of x^3 - double s20 = getSx2(); //sum of x^2 - double s10 = getSx(); //sum of x - double s00 = pointArray.size(); - //sum of x^0 * y^0 ie 1 * number of entries - - double s21 = getSx2y(); //sum of x^2*y - double s11 = getSxy(); //sum of x*y - double s01 = getSy(); //sum of y - - //b = Db/D - return (s40*(s11 * s00 - s01 * s10) - - s30*(s21 * s00 - s01 * s20) + - s20*(s21 * s10 - s11 * s20)) - / - (s40 * (s20 * s00 - s10 * s10) - - s30 * (s30 * s00 - s10 * s20) + - s20 * (s30 * s10 - s20 * s20)); -} - -double LeastSquaresRegression::cTerm() -{ - //notation sjk to mean the sum of x_i^j*y_i^k. - double s40 = getSx4(); //sum of x^4 - double s30 = getSx3(); //sum of x^3 - double s20 = getSx2(); //sum of x^2 - double s10 = getSx(); //sum of x - double s00 = pointArray.size(); - //sum of x^0 * y^0 ie 1 * number of entries - - double s21 = getSx2y(); //sum of x^2*y - double s11 = getSxy(); //sum of x*y - double s01 = getSy(); //sum of y - - //c = Dc/D - return (s40*(s20 * s01 - s10 * s11) - - s30*(s30 * s01 - s10 * s21) + - s20*(s30 * s11 - s20 * s21)) - / - (s40 * (s20 * s00 - s10 * s10) - - s30 * (s30 * s00 - s10 * s20) + - s20 * (s30 * s10 - s20 * s20)); -} - -double LeastSquaresRegression::rSquare() // get r-squared -{ - // 1 - (residual sum of squares / total sum of squares) - return 1 - getSSerr() / getSStot(); -} - - -/*helper methods*/ -double LeastSquaresRegression::getSx() // get sum of x -{ - double Sx = 0; - for (auto it : pointArray) - { - Sx += it.getX(); - } - return Sx; -} - -double LeastSquaresRegression::getSy() // get sum of y -{ - double Sy = 0; - for (auto it : pointArray) - { - Sy += it.getY(); - } - return Sy; -} - -double LeastSquaresRegression::getSx2() // get sum of x^2 -{ - double Sx2 = 0; - for (auto it : pointArray) - { - Sx2 += std::pow (it.getX(), 2); // sum of x^2 - } - return Sx2; -} - -double LeastSquaresRegression::getSx3() // get sum of x^3 -{ - double Sx3 = 0; - for (auto it : pointArray) - { - Sx3 += std::pow (it.getX(), 3); // sum of x^3 - } - return Sx3; -} - -double LeastSquaresRegression::getSx4() // get sum of x^4 -{ - double Sx4 = 0; - for (auto it : pointArray) - { - Sx4 += std::pow (it.getX(), 4); // sum of x^4 - } - return Sx4; -} - -double LeastSquaresRegression::getSxy() // get sum of x*y -{ - double Sxy = 0; - for (auto it : pointArray) - { - Sxy += it.getX() * it.getY(); // sum of x*y - } - return Sxy; -} - -double LeastSquaresRegression::getSx2y() // get sum of x^2*y -{ - double Sx2y = 0; - for (auto it : pointArray) - { - Sx2y += pow(it.getX(), 2) * it.getY(); // sum of x^2*y - } - return Sx2y; -} - -double LeastSquaresRegression::getYMean() // mean value of y -{ - double y_tot = 0; - for (auto it : pointArray) - { - y_tot += it.getY(); - } - return y_tot / pointArray.size(); -} - -double LeastSquaresRegression::getSStot() // total sum of squares -{ - //the sum of the squares of the differences between - //the measured y values and the mean y value - double ss_tot = 0; - for (auto it : pointArray) - { - ss_tot += std::pow (it.getY() - getYMean(), 2); - } - return ss_tot; -} - -double LeastSquaresRegression::getSSerr() // residual sum of squares -{ - //the sum of the squares of te difference between - //the measured y values and the values of y predicted by the equation - double ss_err = 0; - for (auto it : pointArray) - { - ss_err += std::pow (it.getY() - getPredictedY (it.getX()), 2); - } - return ss_err; -} - -double LeastSquaresRegression::getPredictedY (double x) -{ - //returns value of y predicted by the equation for a given value of x - return aTerm() * std::pow(x, 2) + bTerm() * x + cTerm(); -} diff --git a/Modules/gin/utilities/leastsquaresregression.h b/Modules/gin/utilities/leastsquaresregression.h deleted file mode 100755 index 7daefc6..0000000 --- a/Modules/gin/utilities/leastsquaresregression.h +++ /dev/null @@ -1,53 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien, 2010 by Alex Etchells - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -/** - See https://www.codeproject.com/Articles/63170/Least-Squares-Regression-for-Quadratic-Curve-Fitti - for original code - - Derive the equation of a quadratic curve from a series of data points. That is to say, to - determine a, b, and c, where y = ax2 + bx + c. Having determined a, b, and c, I would also - need a value for R-squared (the coefficient of determination). - */ -class LeastSquaresRegression -{ -public: - LeastSquaresRegression() = default; - - void addPoint (double x, double y); - void addPoint (juce::Point point); - void addPoints (Array> points); - - void clear(); - - bool enoughPoints(); - Array getTerms(); - - double aTerm(); - double bTerm(); - double cTerm(); - double rSquare(); - -private: - double getSx(); - double getSy(); - double getSx2(); - double getSx3(); - double getSx4(); - double getSxy(); - double getSx2y(); - double getYMean(); - double getSStot(); - double getSSerr(); - double getPredictedY (double x); - - Array> pointArray; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LeastSquaresRegression) -}; diff --git a/Modules/gin/utilities/linearregression.cpp b/Modules/gin/utilities/linearregression.cpp deleted file mode 100755 index f8619b8..0000000 --- a/Modules/gin/utilities/linearregression.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien, 1998 David C. Swaim - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -LinearRegression::LinearRegression() -{ -} - -LinearRegression::LinearRegression (Array> points) -{ - for (auto p : points) - addPoint (p); - - calculate(); -} - -void LinearRegression::clear() -{ - n = 0; - sumX = 0; - sumY = 0; - sumXsquared = 0; - sumYsquared = 0; - sumXY = 0; - - a = 0; - b = 0; - coefD = 0; - coefC = 0; - stdError = 0; -} - -void LinearRegression::addPoint (juce::Point pnt) -{ - n++; - sumX += pnt.getX(); - sumY += pnt.getY(); - sumXsquared += pnt.getX() * pnt.getX(); - sumYsquared += pnt.getY() * pnt.getY(); - sumXY += pnt.getX() * pnt.getY(); -} - -void LinearRegression::calculate() -{ - if (haveData()) - { - if (std::fabs (n * sumXsquared - sumX * sumX) > DBL_EPSILON) - { - b = (n * sumXY - sumY * sumX) / (n * sumXsquared - sumX * sumX); - a = (sumY - b * sumX) / n; - - double sx = b * (sumXY - sumX * sumY / n); - double sy2 = sumYsquared - sumY * sumY / n; - double sy = sy2 - sx; - - coefD = sx / sy2; - coefC = std::sqrt (coefD); - stdError = std::sqrt(sy / (n - 2)); - } - else - { - a = b = coefD = coefC = stdError = 0.0; - } - } -} diff --git a/Modules/gin/utilities/linearregression.h b/Modules/gin/utilities/linearregression.h deleted file mode 100755 index 6bbee98..0000000 --- a/Modules/gin/utilities/linearregression.h +++ /dev/null @@ -1,49 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien, 1998 David C. Swaim - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -/** Calculates linear regression from a set of points */ -class LinearRegression -{ -public: - LinearRegression(); - LinearRegression (Array> points); - - void addPoint (juce::Point pnt); - void calculate(); - - void clear(); - - bool haveData() const { return n > 2; } - int items() const { return n; } - - double getA() const { return a; } - double getB() const { return b; } - - double getCoefDeterm() const { return coefD; } - double getCoefCorrel() const { return coefC; } - double getStdErrorEst() const { return stdError; } - double estimateY (double x) const { return (a + b * x); } - -protected: - - int n = 0; // number of data points input so far - double sumX = 0; - double sumY = 0; // sums of x and y - double sumXsquared = 0; // sum of x squares - double sumYsquared = 0; // sum y squares - double sumXY = 0; // sum of x*y - - double a = 0; - double b = 0; // coefficients of f(x) = a + b*x - double coefD = 0; // coefficient of determination - double coefC = 0; // coefficient of correlation - double stdError = 0; // standard error of estimate - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LinearRegression) -}; diff --git a/Modules/gin/utilities/messagepack.cpp b/Modules/gin/utilities/messagepack.cpp deleted file mode 100755 index 94fe399..0000000 --- a/Modules/gin/utilities/messagepack.cpp +++ /dev/null @@ -1,442 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -#if _MSC_VER - #pragma warning (push) - #pragma warning (disable: 4310) - #pragma warning (disable: 4100) -#endif - -static void toData (OutputStream& os, const juce::var& obj) -{ - if (obj.isVoid()) - { - os.writeByte (char (0xc0)); - } - else if (obj.isInt() || obj.isInt64()) - { - int64 v = (int64) obj; - if (v >= 0) - { - if (v <= 127) - { - os.writeByte (char (v)); - } - else if (v <= 255) - { - os.writeByte (char (0xcc)); - os.writeByte (char ((unsigned char) v)); - } - else if (v <= 65535) - { - os.writeByte (char (0xcd)); - os.writeShortBigEndian (short ((unsigned short) v)); - } - else if (v <= 4294967295) - { - os.writeByte (char (0xce)); - os.writeIntBigEndian (int ((unsigned int) v)); - } - else - { - os.writeByte (char (0xcf)); - os.writeInt64BigEndian (int64 (v)); - } - } - else - { - if (v >= -7) - { - os.writeByte (char (0xe0 | - char (-v))); - } - else if (v >= -128) - { - os.writeByte (char (0xd0)); - os.writeByte (char (v)); - } - else if (v >= 32768) - { - os.writeByte (char (0xd1)); - os.writeShortBigEndian (short (v)); - } - else if (v >= 2147483648) - { - os.writeByte (char (0xd2)); - os.writeIntBigEndian (int (v)); - } - else - { - os.writeByte (char (0xd3)); - os.writeInt64BigEndian (v); - } - } - } - else if (obj.isBool()) - { - if ((bool) obj) - os.writeByte (char (0xc3)); - else - os.writeByte (char (0xc2)); - } - else if (obj.isDouble()) - { - os.writeByte (char (0xcb)); - os.writeDoubleBigEndian (obj); - } - else if (obj.isString()) - { - auto str = obj.toString(); - auto s = str.toRawUTF8(); - size_t n = str.getNumBytesAsUTF8(); - - if (n <= 31) - { - os.writeByte (char (0xa0 | n)); - os.write (s, n); - } - else if (n <= 255) - { - os.writeByte (char (0xd9)); - os.writeByte (char (n)); - os.write (s, n); - } - else if (n <= 65535) - { - os.writeByte (char (0xda)); - os.writeShortBigEndian (short (n)); - os.write (s, n); - } - else - { - os.writeByte (char (0xdb)); - os.writeIntBigEndian (int (n)); - os.write (s, n); - } - } - else if (obj.isObject() && obj.getDynamicObject() != nullptr) - { - auto& dobj = *obj.getDynamicObject(); - auto& names = dobj.getProperties(); - - int n = names.size(); - - if (n <= 15) - { - os.writeByte (char (0x80 | n)); - } - else if (n <= 65535) - { - os.writeByte (char (0xde)); - os.writeShortBigEndian (short (n)); - } - else - { - os.writeByte (char (0xdf)); - os.writeIntBigEndian (n); - } - - for (auto& itm : names) - { - toData (os, var (itm.name.toString())); - toData (os, itm.value); - } - } - else if (obj.isArray()) - { - auto& arr = *obj.getArray(); - - int n = arr.size(); - - if (n <= 15) - { - os.writeByte (char (0x90 | n)); - } - else if (n <= 65535) - { - os.writeByte (char (0xdc)); - os.writeShortBigEndian (short (n)); - } - else - { - os.writeByte (char (0xdc)); - os.writeIntBigEndian (n); - } - - for (auto& a : arr) - toData (os, a); - } - else if (obj.isBinaryData()) - { - if (auto bd = obj.getBinaryData()) - { - void* s = bd->getData(); - size_t n = bd->getSize(); - - if (n <= 255) - { - os.writeByte (char (0xc4)); - os.writeByte (char (n)); - os.write (s, n); - } - else if (n <= 65535) - { - os.writeByte (char (0xc5)); - os.writeShortBigEndian (short (n)); - os.write (s, n); - } - else - { - os.writeByte (char (0xc6)); - os.writeIntBigEndian (short (n)); - os.write (s, n); - } - } - } - else - { - jassertfalse; - } -} - -static var fromData (InputStream& is); - -static var fromArray (InputStream& is, int n) -{ - Array res; - - for (int i = 0; i < n; i++) - res.add (fromData (is)); - - return res; -} - -static var fromMap (InputStream& is, int n) -{ - auto obj = new DynamicObject(); - - for (int i = 0; i < n; i++) - { - var k = fromData (is); - var v = fromData (is); - - auto ident = k.toString(); - if (ident.isNotEmpty()) - obj->setProperty (ident, v); - } - - return var (obj); -} - -static var fromString (InputStream& is, int n) -{ - MemoryBlock mb; - is.readIntoMemoryBlock (mb, n); - - return String::fromUTF8 ((const char*)mb.getData(), int (mb.getSize())); -} - -static var fromData (InputStream& is) -{ - uint8_t d = uint8_t (is.readByte()); - - if ((d & 0x80) == 0x00) - { - return (int) d; - } - else if ((d & 0xf0) == 0x80) - { - return fromMap (is, d & 0x0f); - } - else if ((d & 0xf0) == 0x90) - { - return fromArray (is, d & 0x0f); - } - else if ((d & 0xe0) == 0xa0) - { - return fromString (is, d & 0x1f); - } - else if (d == 0xc0) - { - return {}; - } - else if (d == 0xc1) - { - jassertfalse; - return {}; - } - else if (d == 0xc2) - { - return false; - } - else if (d == 0xc3) - { - return true; - } - else if (d == 0xc4) - { - uint8_t n = uint8_t (is.readByte()); - MemoryBlock mb; - is.readIntoMemoryBlock (mb, n); - return mb; - } - else if (d == 0xc5) - { - uint16_t n = uint16_t (is.readShortBigEndian()); - MemoryBlock mb; - is.readIntoMemoryBlock (mb, n); - return mb; - } - else if (d == 0xc6) - { - uint32_t n = uint32_t (is.readIntBigEndian()); - MemoryBlock mb; - is.readIntoMemoryBlock (mb, n); - return mb; - } - else if (d == 0xc7) - { - uint8_t n = uint8_t (is.readByte()); - MemoryBlock mb; - is.readIntoMemoryBlock (mb, n + 1); - return mb; - } - else if (d == 0xc8) - { - uint16_t n = uint16_t (is.readShortBigEndian()); - MemoryBlock mb; - is.readIntoMemoryBlock (mb, n + 1); - return mb; - } - else if (d == 0xc9) - { - uint32_t n = uint32_t (is.readIntBigEndian()); - MemoryBlock mb; - is.readIntoMemoryBlock (mb, n + 1); - return mb; - } - else if (d == 0xca) - { - return is.readFloatBigEndian(); - } - else if (d == 0xcb) - { - return is.readDoubleBigEndian(); - } - else if (d == 0xcc) - { - return int (uint8_t (is.readByte())); - } - else if (d == 0xcd) - { - return int (uint8_t (is.readShortBigEndian())); - } - else if (d == 0xce) - { - return int (uint8_t (is.readIntBigEndian())); - } - else if (d == 0xcf) - { - return int (uint8_t (is.readInt64BigEndian())); - } - else if (d == 0xd4) - { - MemoryBlock mb; - is.readIntoMemoryBlock (mb, 1 + 1); - return mb; - } - else if (d == 0xd5) - { - MemoryBlock mb; - is.readIntoMemoryBlock (mb, 1 + 2); - return mb; - } - else if (d == 0xd6) - { - MemoryBlock mb; - is.readIntoMemoryBlock (mb, 1 + 4); - return mb; - } - else if (d == 0xd7) - { - MemoryBlock mb; - is.readIntoMemoryBlock (mb, 1 + 8); - return mb; - } - else if (d == 0xd8) - { - MemoryBlock mb; - is.readIntoMemoryBlock (mb, 1 + 16); - return mb; - } - else if (d == 0xd9) - { - uint8_t n = uint8_t (is.readByte()); - return fromString (is, n); - } - else if (d == 0xda) - { - uint16_t n = uint16_t (is.readShortBigEndian()); - return fromString (is, n); - } - else if (d == 0xdb) - { - uint32_t n = uint32_t (is.readIntBigEndian()); - return fromString (is, int (n)); - } - else if (d == 0xdc) - { - uint16_t n = uint16_t (is.readShortBigEndian()); - return fromArray (is, n); - } - else if (d == 0xdd) - { - uint32_t n = uint32_t (is.readIntBigEndian()); - return fromArray (is, int (n)); - } - else if (d == 0xde) - { - uint16_t n = uint16_t (is.readShortBigEndian()); - return fromArray (is, n); - } - else if (d == 0xdf) - { - uint32_t n = uint32_t (is.readIntBigEndian()); - return fromArray (is, int (n)); - } - else if ((d & 0xe0) == 0xe0) - { - return -(d & 0x1f); - } - - jassertfalse; - return {}; -} -//============================================================================== - -juce::MemoryBlock MessagePack::toMessagePack (const juce::var& obj) -{ - MemoryBlock data; - - { - MemoryOutputStream os (data, false); - toData (os, obj); - } - - return data; -} - -juce::var MessagePack::parse (const juce::MemoryBlock& data) -{ - MemoryInputStream is (data, false); - return fromData (is); -} - -#if _MSC_VER - #pragma warning (pop) -#endif \ No newline at end of file diff --git a/Modules/gin/utilities/messagepack.h b/Modules/gin/utilities/messagepack.h deleted file mode 100755 index c106203..0000000 --- a/Modules/gin/utilities/messagepack.h +++ /dev/null @@ -1,27 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -/** Converts to/from MessagePack and juce::var - - Due to limitations of juce:var, there are no unsigned ints, - object keys can only be strings (non strings will be converted - to string if possible) - - All custom types will be returned as juce::MemoryBlock with the - first byte as the type. - - All strings are assumed to be utf8 - */ -class MessagePack -{ -public: - static juce::MemoryBlock toMessagePack (const juce::var& obj); - - static juce::var parse (const juce::MemoryBlock& data); -}; diff --git a/Modules/gin/utilities/openstreetmaps.cpp b/Modules/gin/utilities/openstreetmaps.cpp deleted file mode 100755 index a833be6..0000000 --- a/Modules/gin/utilities/openstreetmaps.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -OpenStreetMaps::OpenStreetMaps() - : tileSource (OpenStreetMap) -{ - mapTileDir = File::getSpecialLocation (File::tempDirectory).getChildFile ("mapTiles"); - mapTileDir.createDirectory(); -} - -OpenStreetMaps::~OpenStreetMaps() -{ - requests.clear(); - cancelledRequests.clear(); -} - -Image OpenStreetMaps::fetchTile (int zoom, int x, int y) -{ - int mw = getMapWidthTiles (zoom); - x = x % mw; - y = y % mw; - - String fname = String::formatted ("%d-%d-%d-%d.png", (int)tileSource, zoom, x, y); - - File file = mapTileDir.getChildFile (fname); - - if (cache.contains (fname)) - { - return cache[fname]; - } - else if (File (file).existsAsFile()) - { - Image img; - img = ImageFileFormat::loadFrom (file); - - cache.set (fname, img); - - return img; - } - else - { - auto newReq = std::make_unique (zoom, x, y); - - bool pending = false; - for (int i = 0; i < requests.size(); i++) - { - if (*requests[i] == *newReq) - { - pending = true; - break; - } - } - - if (! pending) - { - requests.add (newReq.release()); - startRequest(); - } - - Image img (Image::ARGB, 256, 256, false); - img.clear ({0,0,256,256}, Colour (0xff808080)); - return img; - } -} - -int OpenStreetMaps::getNumServers() -{ - switch (tileSource) - { - case OpenStreetMap: return 3; - case OpenCycleMap: return 3; - case OpenCycleMapTransport: return 3; - case OpenCycleMapLandscape: return 3; - case StamenTerrain: return 1; - case MapQuestOSM: return 4; - case MapQuestOpenAerial: return 4; - case MapQuestOpenStreetMap: return 3; - default: return 0; - } -} - -int OpenStreetMaps::getServer() -{ - for (int i = 0; i < getNumServers(); i++) - { - if (! serversInUse.contains(i)) - return i; - } - return -1; -} - -void OpenStreetMaps::startRequest() -{ - int server = getServer(); - if (server == -1) - return; - - for (int i = 0; i < requests.size(); i++) - { - if (requests[i]->reply == nullptr) - { - char buffer[1024]; - switch (tileSource) - { - case OpenStreetMap: - sprintf(buffer, "http://%c.tile.openstreetmap.org/%d/%d/%d.png", "abc"[server], requests[i]->zoom, requests[i]->x, requests[i]->y); - break; - case OpenCycleMap: - sprintf(buffer, "http://%c.tile.opencyclemap.org/cycle/%d/%d/%d.png", "abc"[server], requests[i]->zoom, requests[i]->x, requests[i]->y); - break; - case OpenCycleMapTransport: - sprintf(buffer, "http://%c.tile2.opencyclemap.org/transport/%d/%d/%d.png", "abc"[server], requests[i]->zoom, requests[i]->x, requests[i]->y); - break; - case OpenCycleMapLandscape: - sprintf(buffer, "http://%c.tile3.opencyclemap.org/landscape/%d/%d/%d.png", "abc"[server], requests[i]->zoom, requests[i]->x, requests[i]->y); - break; - case StamenTerrain: - sprintf(buffer, "http://tile.stamen.com/terrain/%d/%d/%d.png", requests[i]->zoom, requests[i]->x, requests[i]->y); - break; - case MapQuestOSM: - sprintf(buffer, "http://otile%c.mqcdn.com/tiles/1.0.0/map/%d/%d/%d.jpg", "1234"[server], requests[i]->zoom, requests[i]->x, requests[i]->y); - break; - case MapQuestOpenAerial: - sprintf(buffer, "http://otile%c.mqcdn.com/tiles/1.0.0/sat/%d/%d/%d.jpg", "1234"[server], requests[i]->zoom, requests[i]->x, requests[i]->y); - break; - case MapQuestOpenStreetMap: - sprintf(buffer, "http://%c.tile.openstreetmap.org/%d/%d/%d.png", "abc"[server], requests[i]->zoom, requests[i]->x, requests[i]->y); - break; - default: - jassertfalse; - break; - } - - requests[i]->server = server; - - serversInUse.add (server); - - URL url = URL (String (buffer)); - - requests[i]->reply = std::make_unique (buffer, [this] (AsyncDownload* ad, juce::MemoryBlock m, bool ok) - { - finished (ad, m, ok); - }); - - break; - } - } -} - -void OpenStreetMaps::finished (AsyncDownload* reply, juce::MemoryBlock data, bool success) -{ - for (int i = 0; i < requests.size(); i++) - { - if (requests[i]->reply.get() == reply) - { - serversInUse.removeFirstMatchingValue (requests[i]->server); - requests[i]->server = -1; - - if (success) - { - String fname; - fname = String::formatted ("%d-%d-%d-%d.png", (int)tileSource, requests[i]->zoom, requests[i]->x, requests[i]->y); - - Image img = ImageFileFormat::loadFrom (data.getData(), data.getSize()); - if (img.isValid()) - { - cache.set (fname, img); - - File dest = mapTileDir.getChildFile (fname); - dest.replaceWithData (data.getData(), data.getSize()); - - listeners.call (&OpenStreetMaps::Listener::tileFetched, requests[i]->zoom, requests[i]->x, requests[i]->y); - } - - } - requests.remove (i); - break; - } - } - startRequest(); -} - -int OpenStreetMaps::getMapWidthPixels (int zoom) -{ - double numberOfTiles = std::pow (2.0, zoom); - return roundToInt (numberOfTiles * 256); -} - -int OpenStreetMaps::getMapWidthTiles (int zoom) -{ - return roundToInt (std::pow (2.0, zoom)); -} - -juce::Point OpenStreetMaps::coordinateToDisplay (juce::Point coordinate, int zoom) -{ - double numberOfTiles = std::pow (2.0, zoom); - - // LonToX - double x = (coordinate.getX() + 180) * (numberOfTiles * tilesize) / 360.0; - // LatToY - double projection = std::log (std::tan (double_Pi / 4 + degreesToRadians (coordinate.getY()) / 2)); - - double y = (projection / double_Pi); - y = 1 - y; - y = y /2 * (numberOfTiles * tilesize); - - return juce::Point (x, y); -} - -juce::Point OpenStreetMaps::displayToCoordinate (juce::Point point, int zoom) -{ - // longitude - double longitude = (point.getX() * (360 / (std::pow (2.0, zoom) * 256))) - 180; - // latitude - double latitude = point.getY() * (2 / (std::pow (2.0, zoom) * 256)); - - latitude = 1 - latitude; - latitude = latitude * double_Pi; - latitude = radiansToDegrees (std::atan (std::sinh (latitude))); - - juce::Point coord = {longitude, latitude}; - return coord; -} - -juce::Point OpenStreetMaps::tileForCoordinate (double lat, double lng, int zoom) -{ - double zn = static_cast(1 << zoom); - double tx = (lng + 180.0) / 360.0; - double ty = (1.0 - std::log (std::tan (lat * double_Pi / 180.0) + 1.0 / std::cos (lat * double_Pi / 180.0)) / double_Pi) / 2.0; - return {tx * zn, ty * zn}; -} - -void OpenStreetMaps::clearQueue() -{ - while (requests.size() > 0) - cancelledRequests.add (requests.removeAndReturn (0)); - - serversInUse.clear(); -} - -OpenStreetMaps::TileSource OpenStreetMaps::getTileSource() -{ - return tileSource; -} - -void OpenStreetMaps::setTileSource(TileSource t) -{ - tileSource = t; -} diff --git a/Modules/gin/utilities/openstreetmaps.h b/Modules/gin/utilities/openstreetmaps.h deleted file mode 100755 index ec04c6a..0000000 --- a/Modules/gin/utilities/openstreetmaps.h +++ /dev/null @@ -1,100 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -//==============================================================================*/ -// Fetches map files from OSM servers -class OpenStreetMaps -{ -public: - enum TileSource - { - OpenStreetMap, - OpenCycleMap, - OpenCycleMapTransport, - OpenCycleMapLandscape, - StamenTerrain, - MapQuestOSM, - MapQuestOpenAerial, - MapQuestOpenStreetMap, - }; - - OpenStreetMaps(); - ~OpenStreetMaps(); - - /** Set this or map tiles will be stored in the temp directory */ - void setMapTileDir (File f) { mapTileDir = f; } - - Image fetchTile (int zoom, int x, int y); - - int getMapWidthPixels (int zoom); - int getMapWidthTiles (int zoom); - - juce::Point coordinateToDisplay (juce::Point coordinate, int zoom); - juce::Point displayToCoordinate (const juce::Point point, int zoom); - juce::Point tileForCoordinate (double lat, double lng, int zoom); - - void clearQueue(); - - TileSource getTileSource(); - void setTileSource (TileSource t); - - class Listener - { - public: - virtual ~Listener() {} - - virtual void tileFetched (int zoom, int x, int y) = 0; - }; - - void addListener (Listener* listener) { listeners.add (listener); } - void removeListener (Listener* listener) { listeners.remove (listener); } - -private: - void finished (AsyncDownload* task, juce::MemoryBlock data, bool success); - - void startRequest(); - int getNumServers(); - int getServer(); - - class TileReq - { - public: - TileReq (int z_, int x_, int y_) - { - zoom = z_; - x = x_; - y = y_; - server = -1; - } - - bool operator==(const TileReq& b) - { - return zoom == b.zoom && x == b.x && y == b.y; - } - - std::unique_ptr reply; - int zoom; - int x; - int y; - int server; - }; - - OwnedArray requests; - OwnedArray cancelledRequests; - - File mapTileDir; - HashMap cache; - TileSource tileSource; - Array serversInUse; - ListenerList listeners; - - const int tilesize = 256; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenStreetMaps) -}; diff --git a/Modules/gin/utilities/plist.cpp b/Modules/gin/utilities/plist.cpp deleted file mode 100755 index 28c41f1..0000000 --- a/Modules/gin/utilities/plist.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/*============================================================================== - - Copyright 2019 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -var parseData (const XmlElement& e) -{ - if (e.hasTagName ("string")) - { - return e.getAllSubText(); - } - else if (e.hasTagName ("array")) - { - Array res; - - auto c = e.getFirstChildElement(); - while (c != nullptr) - { - res.add (parseData (*c)); - c = c->getNextElement(); - } - - return res; - } - else if (e.hasTagName ("dict")) - { - auto obj = new DynamicObject(); - for (int i = 0; i < e.getNumChildElements(); i += 2) - { - auto key = e.getChildElement (i + 0); - auto val = e.getChildElement (i + 1); - - if (key != nullptr && val != nullptr) - obj->setProperty (key->getAllSubText(), parseData (*val)); - } - - return var (obj); - } - else if (e.hasTagName ("data")) - { - MemoryBlock mb; - - { - MemoryOutputStream os (mb, true); - Base64::convertFromBase64 (os, e.getAllSubText()); - } - - return mb; - } - else if (e.hasTagName ("date")) - { - return e.getAllSubText(); - } - else if (e.hasTagName ("real")) - { - return e.getAllSubText().getDoubleValue(); - } - else if (e.hasTagName ("integer")) - { - return e.getAllSubText().getIntValue(); - } - else if (e.hasTagName ("true")) - { - return true; - } - else if (e.hasTagName ("false")) - { - return false; - } - - jassertfalse; - return {}; -} - -var parsePlist (const File& f) -{ - XmlDocument doc (f); - if (auto e = doc.getDocumentElement()) - return parsePlist (*e); - return {}; -} - -var parsePlist (const String& s) -{ - XmlDocument doc (s); - if (auto e = doc.getDocumentElement()) - return parsePlist (*e); - return {}; -} - -var parsePlist (const XmlElement& e) -{ - if (auto dict = e.getChildByName ("dict")) - { - auto obj = new DynamicObject(); - for (int i = 0; i < dict->getNumChildElements(); i += 2) - { - auto key = dict->getChildElement (i + 0); - auto val = dict->getChildElement (i + 1); - - if (key != nullptr && val != nullptr) - obj->setProperty (key->getAllSubText(), parseData (*val)); - } - - return var (obj); - } - return {}; -} diff --git a/Modules/gin/utilities/plist.h b/Modules/gin/utilities/plist.h deleted file mode 100755 index 518c577..0000000 --- a/Modules/gin/utilities/plist.h +++ /dev/null @@ -1,16 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -//============================================================================== -juce::var parsePlist (const juce::File& f); - -juce::var parsePlist (const juce::String& s); - -juce::var parsePlist (const juce::XmlElement& f); - diff --git a/Modules/gin/utilities/realtimeasyncupdater.cpp b/Modules/gin/utilities/realtimeasyncupdater.cpp deleted file mode 100755 index 3db5791..0000000 --- a/Modules/gin/utilities/realtimeasyncupdater.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -//============================================================================== -class RealtimeAsyncUpdater::Impl : public Thread -{ -public: - Impl() : Thread ("RealtimeAsyncUpdater") - { - startThread(); - next = 0; - } - - ~Impl() override - { - signalThreadShouldExit (); - event.signal(); - stopThread (1000); - } - - void registerUpdater (RealtimeAsyncUpdater* ras) - { - ScopedLock sl (lock); - updaters.add (ras); - } - - void unregisterUpdater (RealtimeAsyncUpdater* ras) - { - ScopedLock sl (lock); - updaters.removeFirstMatchingValue (ras); - } - - void signal (RealtimeAsyncUpdater& ras) - { - static PerformanceCounter counter {"signal", 1000}; - counter.start(); - ras.order = ++next; - event.signal(); - counter.stop(); - } - -private: - CriticalSection lock; - Array updaters; - WaitableEvent event; - Atomic next; - - void run() override - { - while (true) - { - event.wait (-1); - - if (threadShouldExit()) - break; - - WeakReference weakSelf = this; - MessageManager::getInstance()->callAsync ([this, weakSelf] { - if (weakSelf != nullptr) - fireCallbacks(); - }); - } - } - - void fireCallbacks() - { - Array dirtyUpdaters; - - ScopedLock sl (lock); - for (auto au : updaters) - if (au->triggered.get()) - dirtyUpdaters.add (au); - - std::sort (dirtyUpdaters.begin(), dirtyUpdaters.end(), - [] (const RealtimeAsyncUpdater* a, const RealtimeAsyncUpdater* b) -> bool - { - return a->order.get() < b->order.get(); - }); - - for (auto au : dirtyUpdaters) - { - au->triggered = false; - au->handleAsyncUpdate(); - } - } - - JUCE_DECLARE_WEAK_REFERENCEABLE (Impl) -}; - -//============================================================================== -RealtimeAsyncUpdater::RealtimeAsyncUpdater() -{ - impl->registerUpdater (this); -} - -RealtimeAsyncUpdater::~RealtimeAsyncUpdater() -{ - impl->unregisterUpdater (this); -} - -void RealtimeAsyncUpdater::triggerAsyncUpdate() -{ - if (! triggered.get()) - { - triggered = true; - impl->signal (*this); - } -} - -void RealtimeAsyncUpdater::cancelPendingUpdate() noexcept -{ - triggered = false; -} - -void RealtimeAsyncUpdater::handleUpdateNowIfNeeded() -{ - if (triggered.get()) - { - triggered = false; - handleAsyncUpdate(); - } -} - -bool RealtimeAsyncUpdater::isUpdatePending() const noexcept -{ - return triggered.get(); -} diff --git a/Modules/gin/utilities/realtimeasyncupdater.h b/Modules/gin/utilities/realtimeasyncupdater.h deleted file mode 100755 index 24d9cef..0000000 --- a/Modules/gin/utilities/realtimeasyncupdater.h +++ /dev/null @@ -1,36 +0,0 @@ -/*============================================================================== - - Copyright 2020 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -class RealtimeAsyncUpdater -{ -public: - RealtimeAsyncUpdater(); - - virtual ~RealtimeAsyncUpdater(); - - void triggerAsyncUpdate(); - - void cancelPendingUpdate() noexcept; - - void handleUpdateNowIfNeeded(); - - bool isUpdatePending() const noexcept; - - virtual void handleAsyncUpdate() = 0; - -private: - //============================================================================== - class Impl; - SharedResourcePointer impl; - - Atomic triggered; - Atomic order; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RealtimeAsyncUpdater) -}; diff --git a/Modules/gin/utilities/sharedmemory.cpp b/Modules/gin/utilities/sharedmemory.cpp deleted file mode 100755 index f7f4855..0000000 --- a/Modules/gin/utilities/sharedmemory.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#if JUCE_WINDOWS -typedef enum _SECTION_INFORMATION_CLASS -{ - SectionBasicInformation, - SectionImageInformation -} SECTION_INFORMATION_CLASS; - -typedef struct _SECTION_BASIC_INFORMATION { - PVOID base; - ULONG attributes; - LARGE_INTEGER size; -} SECTION_BASIC_INFORMATION; - -typedef DWORD (WINAPI* NTQUERYSECTION) (HANDLE, SECTION_INFORMATION_CLASS, PVOID, ULONG, PULONG); - -class SharedMemory::Impl -{ -public: - Impl (String name, int sz) : size (sz) - { - String shareName = "Local\\" + File::createLegalFileName (name); - - fileMapping = OpenFileMappingW (FILE_MAP_ALL_ACCESS, FALSE, shareName.toWideCharPointer()); - if (fileMapping == nullptr) - fileMapping = CreateFileMappingW (INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, sz, shareName.toWideCharPointer()); - - if (HMODULE dll = LoadLibrary ("ntdll.dll")) - { - NTQUERYSECTION ntQuerySection = (NTQUERYSECTION) GetProcAddress (dll, "NtQuerySection"); - if (ntQuerySection != nullptr) - { - SECTION_BASIC_INFORMATION SectionInfo = { 0 }; - ntQuerySection (fileMapping, SectionBasicInformation, &SectionInfo, sizeof (SectionInfo), 0); - - if (SectionInfo.size.QuadPart > 0) - size = int (SectionInfo.size.QuadPart); - } - FreeLibrary (dll); - } - - data = MapViewOfFile (fileMapping, FILE_MAP_ALL_ACCESS, 0, 0, size); - } - - ~Impl() - { - if (data != nullptr) - UnmapViewOfFile (data); - - if (fileMapping != nullptr) - CloseHandle (fileMapping); - } - - static void remove (const String& name) - { - ignoreUnused (name); - } - - HANDLE fileMapping = nullptr; - - int size = 0; - void* data = nullptr; -}; -#else -class SharedMemory::Impl -{ -public: - Impl (String name, int sz) : size (sz) - { - bool needsInit = false; - - shareName = "/jshm" + File::createLegalFileName (name); - - fd = shm_open (shareName.toRawUTF8(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); - if (fd == -1) - fd = shm_open (shareName.toRawUTF8(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); - else - needsInit = true; - - if (fd == -1) - { - size = 0; - return; - } - - if (needsInit && ftruncate (fd, size) == -1) - { - size = 0; - return; - } - - struct stat statbuf; - if (fstat (fd, &statbuf) == -1) - { - size = 0; - return; - } - - size = int (statbuf.st_size); - - data = mmap (nullptr, size_t (size), PROT_WRITE, MAP_SHARED, fd, 0); - jassert (data != nullptr); - - if (data != nullptr && needsInit) - memset (data, 0, sizeof (data)); - } - - ~Impl() - { - if (data != nullptr) - munmap (data, size_t (size)); - - if (fd != -1) - close (fd); - - shm_unlink (shareName.toRawUTF8()); - } - - static void remove (const String& name) - { - String shareName = "/jshm" + File::createLegalFileName (name); - shm_unlink (shareName.toRawUTF8()); - } - - String shareName; - int size; - void* data = nullptr; - int fd; -}; -#endif - -SharedMemory::SharedMemory (const String& name, int size) -{ - impl = std::make_unique (name, size); -} - -SharedMemory::~SharedMemory() -{ -} - -void* SharedMemory::getData() -{ - return impl->data; -} - -int SharedMemory::getSize() -{ - return impl->size; -} - -void SharedMemory::remove (const String& name) -{ - Impl::remove (name); -} diff --git a/Modules/gin/utilities/sharedmemory.h b/Modules/gin/utilities/sharedmemory.h deleted file mode 100755 index 568bccc..0000000 --- a/Modules/gin/utilities/sharedmemory.h +++ /dev/null @@ -1,37 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -/** Creates a block of shared memory. The first one to create the block sets the size - otherwise it is ignored. The block may be a different size than requested, especially - if it was already created. - - On Unix based OSes, if a process using the block crashes, the block will leak. Clean - it up later with remove() and it will be deleted when the last process stops using it. - (No new processes will be able to attach) - - On Windows the memory block will always disappear when the final process closes the - handle / crashes. - */ -class SharedMemory -{ -public: - SharedMemory (const String& name, int size); - ~SharedMemory(); - - static void remove (const String& name); - - void* getData(); - int getSize(); - -private: - class Impl; - std::unique_ptr impl; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedMemory) -}; diff --git a/Modules/gin/utilities/spline.cpp b/Modules/gin/utilities/spline.cpp deleted file mode 100755 index 9f0658e..0000000 --- a/Modules/gin/utilities/spline.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien, Devin Lane - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -/* "THE BEER-WARE LICENSE" (Revision 42): Devin Lane wrote this file. As long as you retain - * this notice you can do whatever you want with this stuff. If we meet some day, and you - * think this stuff is worth it, you can buy me a beer in return. */ - - -Spline::Spline (const Array>& points) -{ - jassert (points.size() >= 3); // "Must have at least three points for interpolation" - points.size (); - int n = points.size() - 1; - - Array b, d, a, c, l, u, z, h; - - a.resize (n); - b.resize (n); - c.resize (n + 1); - d.resize (n); - h.resize (n + 1); - l.resize (n + 1); - u.resize (n + 1); - z.resize (n + 1); - - l.set (0, 1.0); - u.set (0, 0.0); - z.set (0, 0.0); - h.set (0, points[1].getX() - points[0].getX()); - - for (int i = 1; i < n; i++) - { - h.set (i, points[i+1].getX() - points[i].getX()); - l.set (i, (2 * (points[i+1].getX() - points[i-1].getX())) - (h[i-1]) * u[i-1]); - u.set (i, l[i] == 0 ? 0 :h[i] / l[i]); - a.set (i, h[i] == 0 || h[i-1] == 0 ? 0 : (3.0 / (h[i])) * (points[i+1].getY() - points[i].getY()) - (3.0 / (h[i-1])) * (points[i].getY() - points[i-1].getY())); - z.set (i, l[i] == 0 ? 0 : (a[i] - (h[i-1]) * z[i-1]) / l[i]); - } - - l.set (n, 1.0); - z.set (n, 0.0); - c.set (n, 0.0); - - for (int j = n - 1; j >= 0; j--) - { - c.set (j, z[j] - u[j] * c[j+1]); - b.set (j, h[j] == 0 ? 0 : (points[j+1].getY() - points[j].getY()) / (h[j]) - ((h[j]) * (c[j+1] + 2.0 * c[j])) / 3.0); - d.set (j, h[j] == 0 ? 0 : (c[j+1] - c[j]) / (3.0 * h[j])); - } - - for (int i = 0; i < n; i++) - elements.add (Element (points[i].getX(), points[i].getY(), b[i], c[i], d[i])); -} - -double Spline::operator[] (double x) const -{ - return interpolate (x); -} - -double Spline::interpolate (double x) const -{ - if (elements.size() == 0) - return 0.0; - - int i; - for (i = 0; i < elements.size(); i++) - { - if (! (elements[i] < x)) - break; - } - if (i != 0) i--; - - return elements[i].eval (x); -} diff --git a/Modules/gin/utilities/spline.h b/Modules/gin/utilities/spline.h deleted file mode 100755 index 5b5b656..0000000 --- a/Modules/gin/utilities/spline.h +++ /dev/null @@ -1,47 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien, Devin Lane - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -/** Cubic spline interpolation is a simple way to obtain a smooth curve from a set of - discrete points. It has both C1 (first derivative) and C2 (second derivative) continuity, - enabling it to produce a continuous piecewise function given a set of data points. - - Add points in increasing x order */ -class Spline -{ -public: - Spline (const Array>& points); - - double operator[] (double x) const; - double interpolate (double x) const; - - class Element - { - public: - Element (double x_ = 0) : x (x_) {} - - Element (double x_, double a_, double b_, double c_, double d_) - : x (x_), a (a_), b (b_), c (c_), d (d_) {} - - double eval (double xx) const - { - double xix (xx - x); - return a + b * xix + c * (xix * xix) + d * (xix * xix * xix); - } - - bool operator< (const Element& e) const { return x < e.x; } - bool operator< (const double xx) const { return x < xx; } - - double x = 0, a = 0, b = 0, c = 0, d = 0; - }; - -private: - Array elements; - - JUCE_LEAK_DETECTOR (Spline) -}; diff --git a/Modules/gin/utilities/systemsemaphore.cpp b/Modules/gin/utilities/systemsemaphore.cpp deleted file mode 100755 index b694bb6..0000000 --- a/Modules/gin/utilities/systemsemaphore.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#ifdef JUCE_WINDOWS -class SystemSemaphore::Impl -{ -public: - Impl (String name) - { - ignoreUnused (name); - jassertfalse; - // not implemented yet - } - - ~Impl() - { - } - - bool lock() - { - return false; - } - - bool unlock() - { - return false; - } - - bool isValid() - { - return false; - } -}; - -#else -class SystemSemaphore::Impl -{ -public: - Impl (String name) - { - String shareName = "/jsem" + File::createLegalFileName (name); - sem = sem_open (shareName.toRawUTF8(), O_CREAT, 0644, 1); - - jassert (sem != SEM_FAILED); - } - - ~Impl() - { - sem_close (sem); - } - - bool lock() - { - if (! locked) - { - sem_wait (sem); - locked = true; - return true; - } - return false; - } - - bool unlock() - { - if (locked) - { - sem_post (sem); - locked = false; - return true; - } - return false; - } - - bool isValid() - { - return sem != SEM_FAILED; - } - - sem_t* sem = SEM_FAILED; - bool locked = false; -}; -#endif - -SystemSemaphore::SystemSemaphore (const String& name) -{ - impl = std::make_unique (name); -} - -SystemSemaphore::~SystemSemaphore() -{ -} - -bool SystemSemaphore::lock() -{ - return impl->lock(); -} - -bool SystemSemaphore::unlock() -{ - return impl->unlock(); -} - -bool SystemSemaphore::isValid() -{ - return impl->isValid(); -} diff --git a/Modules/gin/utilities/systemsemaphore.h b/Modules/gin/utilities/systemsemaphore.h deleted file mode 100755 index 2dc4c62..0000000 --- a/Modules/gin/utilities/systemsemaphore.h +++ /dev/null @@ -1,29 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -/* - * This is not finished / implemented - */ -class SystemSemaphore -{ -public: - SystemSemaphore (const String& name); - ~SystemSemaphore(); - - bool lock(); - bool unlock(); - - bool isValid(); - -private: - class Impl; - std::unique_ptr impl; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SystemSemaphore) -}; diff --git a/Modules/gin/utilities/threading.cpp b/Modules/gin/utilities/threading.cpp deleted file mode 100755 index a754089..0000000 --- a/Modules/gin/utilities/threading.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -//============================================================================== -class BackgroundCaller : private Thread, - private AsyncUpdater -{ -public: - BackgroundCaller (std::function func) - : Thread ("BackgroundCaller"), function (func) - { - startThread(); - } - - ~BackgroundCaller() override - { - stopThread (1000); - } - - void run() override - { - function(); - triggerAsyncUpdate(); - } - - void handleAsyncUpdate() override - { - delete this; - } - - std::function function; -}; - -void callInBackground (std::function function) -{ - new BackgroundCaller (function); -} diff --git a/Modules/gin/utilities/threading.h b/Modules/gin/utilities/threading.h deleted file mode 100755 index ec5e686..0000000 --- a/Modules/gin/utilities/threading.h +++ /dev/null @@ -1,48 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -//============================================================================== -// Calls a function in background -void callInBackground (std::function function); - -//============================================================================== -// Run a for loop split between each core. -// for (int i = 0; i < 10; i++) becomes multiThreadedFor (0, 10, 1, threadPool, [&] (int i) {}); -// Make sure each iteration of the loop is independant -template -void multiThreadedFor (T start, T end, T interval, ThreadPool* threadPool, std::function callback) -{ - if (threadPool == nullptr) - { - for (int i = start; i < end; i += interval) - callback (i); - } - else - { - int num = threadPool->getNumThreads(); - - WaitableEvent wait; - Atomic threadsRunning (num); - - for (int i = 0; i < num; i++) - { - threadPool->addJob ([i, &callback, &wait, &threadsRunning, start, end, interval, num] - { - for (int j = start + interval * i; j < end; j += interval * num) - callback (j); - - int stillRunning = --threadsRunning; - if (stillRunning == 0) - wait.signal(); - }); - } - - wait.wait(); - } -} diff --git a/Modules/gin/utilities/util.cpp b/Modules/gin/utilities/util.cpp deleted file mode 100755 index b484b07..0000000 --- a/Modules/gin/utilities/util.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -Colour goldenRatioColor (int idx) -{ - double h = std::fmod (idx * 0.618033988749895, 1); - return Colour (float (h), 0.8f, 0.95f, 1.0f); -} - -//============================================================================== -int versionStringToInt (const String& versionString) -{ - StringArray parts; - parts.addTokens (versionString, ".", ""); - parts.trim(); - parts.removeEmptyStrings(); - - int res = 0; - - for (auto part : parts) - res = (res << 8) + part.getIntValue(); - - return res; -} - -//============================================================================== -class DelayedLambdaHelper : public Timer -{ -public: - DelayedLambdaHelper (std::function& cb, int ms) - : callback (cb) - { - startTimer (ms); - } - - void timerCallback() override - { - callback(); - delete this; - } - - std::function callback; -}; - -void delayedLambda (std::function callback, int delayMS) -{ - new DelayedLambdaHelper (callback, delayMS); -} diff --git a/Modules/gin/utilities/util.h b/Modules/gin/utilities/util.h deleted file mode 100755 index 0f55a5c..0000000 --- a/Modules/gin/utilities/util.h +++ /dev/null @@ -1,267 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -//============================================================================== -inline bool compareAndReset (bool& flag) -{ - if (flag) - { - flag = false; - return true; - } - return false; -} - -inline float calculateRMS (const float* values, int n) -{ - float rms = 0; - - for (int i = 0; i < n; i++) - rms += values[i] * values[i]; - - return std::sqrt ((1.0f / n) * rms); -} - -inline float calculateMedian (const float* values, int n) -{ - Array f; - f.insertArray (0, values, n); - f.sort(); - - if (f.size() % 2 == 0) - return (f[f.size() / 2] + f[f.size() / 2 - 1]) / 2.0f; - - return f[f.size() / 2]; -} - -//============================================================================== -// Fisher-Yates Shuffle -template -void shuffleArray (Random& r, T array) -{ - const int n = array.size(); - for (int i = n - 1; i >= 1; i--) - { - int j = r.nextInt (i + 1); - array.swap (i, j); - } -} - -//============================================================================== -// Based on reference implementation of Perlin Noise by Ken Perlin -// http://mrl.nyu.edu/~perlin/paper445.pdf -template -class PerlinNoise -{ -public: - PerlinNoise() - { - p = { 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142, - 8,99,37,240,21,10,23,190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117, - 35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71, - 134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41, - 55,46,245,40,244,102,143,54, 65,25,63,161,1,216,80,73,209,76,132,187,208, 89, - 18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226, - 250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182, - 189,28,42,223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, - 43,172,9,129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246, - 97,228,251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239, - 107,49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, - 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 }; - - p.addArray (p); - } - - PerlinNoise (unsigned int seed) - { - Random r (seed); - - for (int i = 0; i <= 255; i++) - p.add (i); - - shuffleArray (r, p); - - p.addArray (p); - } - - T noise (T x, T y = 0, T z = 0) - { - int X = (int) std::floor (x) & 255; - int Y = (int) std::floor (y) & 255; - int Z = (int) std::floor (z) & 255; - - x -= std::floor (x); - y -= std::floor (y); - z -= std::floor (z); - - T u = fade (x); - T v = fade (y); - T w = fade (z); - - int A = p[X] + Y; - int AA = p[A] + Z; - int AB = p[A + 1] + Z; - int B = p[X + 1] + Y; - int BA = p[B] + Z; - int BB = p[B + 1] + Z; - - // Add blended results from 8 corners of cube - T res = lerp (w, - lerp (v, lerp (u, grad(p[AA], x, y, z), - grad (p[BA], x-1, y, z)), - lerp (u, grad (p[AB], x, y-1, z), - grad (p[BB], x-1, y-1, z))), - lerp (v, lerp (u, grad (p[AA+1], x, y, z-1), - grad (p[BA+1], x-1, y, z-1)), - lerp (u, grad (p[AB+1], x, y-1, z-1), - grad (p[BB+1], x-1, y-1, z-1)))); - - return T ((res + 1.0) / 2.0); - } - -private: - T fade (T t) - { - return t * t * t * (t * (t * 6 - 15) + 10); - } - - T lerp (T t, T a, T b) - { - return a + t * (b - a); - } - - T grad (int hash, T x, T y, T z) - { - int h = hash & 15; - T u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z; - return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); - } - - Array p; -}; - -//============================================================================== -// Keeps a rolling average of a series of numbers -class RollingAverage -{ -public: - RollingAverage (int numVals_) - : numVals (numVals_) - { - } - - double average (double nextValue) - { - return (nextValue + numVals * currAvg) / (double)(numVals + 1); - } - - double getAverage() - { - return currAvg; - } - - void setAverage (double avg) - { - currAvg = avg; - } - -private: - int numVals = 0; - double currAvg = 0.0; -}; - -//============================================================================== -// Returns the next colour in a set where the hues differ by the golden ratio. -// Good for coming up with a random set of colours -Colour goldenRatioColor (int idx); - -//============================================================================== -// Async Download. Doesn't have the main thread pause the URL::downloadToFile has -class AsyncDownload : private Thread, - private AsyncUpdater -{ -public: - AsyncDownload (String url_, std::function cb_, int timeoutMS_ = 0) - : Thread ("AsyncDownload"), url (url_), cb (cb_), timeoutMS (timeoutMS_) - { - startThread(); - } - - AsyncDownload (URL url_, std::function cb_, int timeoutMS_ = 0) - : Thread ("AsyncDownload"), url (url_), cb (cb_), timeoutMS (timeoutMS_) - { - startThread(); - } - - ~AsyncDownload() override - { - stopThread (100); - } - - void run() override - { - ok = readEntireBinaryStream (data); - triggerAsyncUpdate(); - } - - bool readEntireBinaryStream (MemoryBlock& destData, bool usePostCommand = false) - { - const std::unique_ptr in (url.isLocalFile() ? url.getLocalFile().createInputStream() : url.createInputStream (usePostCommand, nullptr, nullptr, {}, timeoutMS)); - - if (in != nullptr) - { - in->readIntoMemoryBlock (destData); - return true; - } - - return false; - } - - void handleAsyncUpdate() override - { - if (cb) - cb (this, data, ok); - } - - URL url; - std::function cb; - int timeoutMS = 0; - bool ok = false; - juce::MemoryBlock data; -}; - -//============================================================================== -// Time Profiler -- get a quick idea how long something takes -class TimeProfiler -{ -public: - TimeProfiler (const String& name_) : - name (name_), start (Time::getMillisecondCounterHiRes()) {} - - ~TimeProfiler() - { - DBG (name + String::formatted (" %.2fs", (Time::getMillisecondCounterHiRes() - start) / 1000.0)); - } - -private: - String name; - double start; -}; - -//============================================================================== -template -inline bool almostEqual (T a, T b, T precision = T (0.00001)) -{ - return std::abs (a - b) < precision; -} - -int versionStringToInt (const String& versionString); - -//============================================================================== -void delayedLambda (std::function callback, int delayMS); diff --git a/Modules/gin/utilities/valuetreeobject.cpp b/Modules/gin/utilities/valuetreeobject.cpp deleted file mode 100755 index 4d342b5..0000000 --- a/Modules/gin/utilities/valuetreeobject.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -std::function ValueTreeObject::factory; - -ValueTreeObject::ValueTreeObject (const ValueTree& state_) - : state (state_) -{ - for (auto c : state) - { - if (auto* newObj = factory (c.getType(), c)) - { - newObj->parent = this; - children.add (newObj); - } - else - { - jassertfalse; // type missing in factory - } - } - - state.addListener (this); -} - -void ValueTreeObject::valueTreePropertyChanged (ValueTree& p, const Identifier& i) -{ - ignoreUnused (p, i); -} - -void ValueTreeObject::valueTreeChildAdded (ValueTree& p, ValueTree& c) -{ - if (p == state) - { - if (auto* newObj = factory (c.getType(), c)) - { - newObj->parent = this; - children.insert (p.indexOf (c), newObj); - } - else - { - jassertfalse; // type missing in factory - } - } -} - -void ValueTreeObject::valueTreeChildRemoved (ValueTree& p, ValueTree& c, int i) -{ - ignoreUnused (c); - - if (p == state) - children.remove (i); -} - -void ValueTreeObject::valueTreeChildOrderChanged (ValueTree& p, int oldIndex, int newIndex) -{ - if (p == state) - children.move (oldIndex, newIndex); -} - -void ValueTreeObject::valueTreeParentChanged (ValueTree&) -{ -} - -void ValueTreeObject::valueTreeRedirected (ValueTree&) -{ -} diff --git a/Modules/gin/utilities/valuetreeobject.h b/Modules/gin/utilities/valuetreeobject.h deleted file mode 100755 index e4ed320..0000000 --- a/Modules/gin/utilities/valuetreeobject.h +++ /dev/null @@ -1,97 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -//============================================================================== -/* Mirrors a ValueTree in Objects */ -class ValueTreeObject : private ValueTree::Listener -{ -public: - ValueTreeObject (const ValueTree& state); - - ValueTree& getState() { return state; } - - static std::function factory; - -public: - const OwnedArray& getChildren() const { return children; } - - template - TargetClass* findParentOfType() const - { - auto* p = parent; - while (p != nullptr) - { - if (auto* res = dynamic_cast (parent)) - return res; - - p = p->parent; - } - - return nullptr; - } - - template - Array findChildrenOfClass() const - { - Array res; - - for (auto* c : children) - if (auto* t = dynamic_cast (c)) - res.add (t); - - return res; - } - - template - int countChildrenOfClass() const - { - int count = 0; - - for (auto* c : children) - if (auto* t = dynamic_cast (c)) - count++; - - return count; - } - - template - TargetClass* findChildOfClass (int idx) const - { - int count = 0; - - for (auto* c : children) - { - if (auto* t = dynamic_cast (c)) - { - if (count == idx) - return t; - - count++; - } - } - - return nullptr; - } - -private: - void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const Identifier& property) override; - void valueTreeChildAdded (ValueTree& parentTree, ValueTree& childWhichHasBeenAdded) override; - void valueTreeChildRemoved (ValueTree& parentTree, ValueTree& childWhichHasBeenRemoved, int indexFromWhichChildWasRemoved) override; - void valueTreeChildOrderChanged (ValueTree& parentTreeWhoseChildrenHaveMoved, int oldIndex, int newIndex) override; - void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) override; - void valueTreeRedirected (ValueTree& treeWhichHasBeenChanged) override; - -private: - ValueTree state; - ValueTreeObject* parent = nullptr; - - OwnedArray children; - - JUCE_LEAK_DETECTOR (ValueTreeObject) -}; diff --git a/Modules/gin/utilities/valuetreeutilities.cpp b/Modules/gin/utilities/valuetreeutilities.cpp deleted file mode 100755 index 5de6c6f..0000000 --- a/Modules/gin/utilities/valuetreeutilities.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/*============================================================================== - - Copyright 2019 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -//============================================================================== -static var toVar (const juce::ValueTree& v) -{ - auto obj = new DynamicObject(); - - obj->setProperty ("_name", v.getType().toString()); - - Array children; - - for (auto c : v) - children.add (toVar (c)); - - if (children.size() > 0) - obj->setProperty ("_children", children); - - for (int i = 0; i < v.getNumProperties(); i++) - { - auto name = v.getPropertyName (i).toString(); - auto val = v.getProperty (name, {}); - - if (auto mb = val.getBinaryData()) - { - obj->setProperty ("base64:" + name, mb->toBase64Encoding()); - } - else - { - // These types can't be stored as JSON! - jassert (! val.isObject()); - jassert (! val.isMethod()); - jassert (! val.isArray()); - - obj->setProperty (name, val.toString()); - } - } - - return var (obj); -} - -juce::String valueTreeToJSON (const juce::ValueTree& v) -{ - auto obj = toVar (v); - return JSON::toString (obj); -} - -//============================================================================== -juce::ValueTree fromVar (const juce::var& obj) -{ - if (auto dobj = obj.getDynamicObject()) - { - ValueTree v (dobj->getProperty ("_name").toString()); - - auto c = dobj->getProperty ("_children"); - if (c.isArray()) - for (auto& child : *c.getArray()) - v.addChild (fromVar (child), -1, nullptr); - - auto properties = dobj->getProperties(); - for (auto itr : properties) - { - auto name = itr.name.toString(); - if (name == "_name" || name == "_children") continue; - - if (name.startsWith ("base64:")) - { - MemoryBlock mb; - if (mb.fromBase64Encoding (itr.value.toString())) - v.setProperty (name.substring (7), var (mb), nullptr); - } - else - { - v.setProperty (name, var (itr.value), nullptr); - } - } - - return v; - } - return {}; -} - -juce::ValueTree valueTreeFromJSON (const juce::String& jsonText) -{ - var obj = JSON::parse (jsonText); - if (obj.isObject()) - return fromVar (obj); - return {}; -} diff --git a/Modules/gin/utilities/valuetreeutilities.h b/Modules/gin/utilities/valuetreeutilities.h deleted file mode 100755 index 9725d4b..0000000 --- a/Modules/gin/utilities/valuetreeutilities.h +++ /dev/null @@ -1,173 +0,0 @@ -/*============================================================================== - - Copyright 2018 by Roland Rabien - For more information visit www.rabiensoftware.com - - ==============================================================================*/ - -#pragma once - -//============================================================================== -juce::String valueTreeToJSON (const juce::ValueTree& v); - -juce::ValueTree valueTreeFromJSON (const juce::String& jsonText); - -//============================================================================== -class LambdaValueTreeListener : public ValueTree::Listener -{ -public: - LambdaValueTreeListener (ValueTree& v_) - : vt (v_) - { - vt.addListener (this); - } - - ~LambdaValueTreeListener() override - { - vt.removeListener (this); - } - - std::function onValueTreePropertyChanged; - std::function onValueTreeChildAdded; - std::function onValueTreeChildRemoved; - std::function onValueTreeChildOrderChanged; - std::function onValueTreeParentChanged; - std::function onValueTreeRedirected; - -private: - void valueTreePropertyChanged (ValueTree&v , const Identifier& i) override - { - if (onValueTreePropertyChanged) - onValueTreePropertyChanged (v, i); - } - - void valueTreeChildAdded (ValueTree& p, ValueTree& c) override - { - if (onValueTreeChildAdded) - onValueTreeChildAdded (p, c); - } - - void valueTreeChildRemoved (ValueTree& p, ValueTree& c, int n) override - { - if (onValueTreeChildRemoved) - onValueTreeChildRemoved (p, c, n); - - } - - void valueTreeChildOrderChanged (ValueTree& v, int a, int b) override - { - if (onValueTreeChildOrderChanged) - onValueTreeChildOrderChanged (v, a, b); - } - - void valueTreeParentChanged (ValueTree& v) override - { - if (onValueTreeParentChanged) - onValueTreeParentChanged (v); - } - - void valueTreeRedirected (ValueTree& v) override - { - if (onValueTreeRedirected) - onValueTreeRedirected (v); - } - - ValueTree& vt; -}; - -//============================================================================== -class AsyncLambdaValueTreeListener : public ValueTree::Listener -{ -public: - AsyncLambdaValueTreeListener (ValueTree& v_) - : vt (v_) - { - vt.addListener (this); - } - - ~AsyncLambdaValueTreeListener() override - { - vt.removeListener (this); - } - - std::function onValueTreePropertyChanged; - std::function onValueTreeChildAdded; - std::function onValueTreeChildRemoved; - std::function onValueTreeChildOrderChanged; - std::function onValueTreeParentChanged; - std::function onValueTreeRedirected; - -private: - void valueTreePropertyChanged (ValueTree& v, const Identifier& i) override - { - ValueTree vc = v; - Identifier ic = i; - WeakReference weakThis (this); - MessageManager::getInstance()->callAsync ([this, weakThis, vc, ic] - { - if (weakThis != nullptr && onValueTreePropertyChanged) - onValueTreePropertyChanged (vc, ic); - }); - } - - void valueTreeChildAdded (ValueTree& p, ValueTree& c) override - { - ValueTree pc = p; - ValueTree cc = c; - WeakReference weakThis (this); - MessageManager::getInstance()->callAsync ([this, weakThis, pc, cc] - { - if (weakThis != nullptr && onValueTreeChildAdded) - onValueTreeChildAdded (pc, cc); - }); - } - - void valueTreeChildRemoved (ValueTree& p, ValueTree& c, int n) override - { - ValueTree pc = p; - ValueTree cc = c; - WeakReference weakThis (this); - MessageManager::getInstance()->callAsync ([this, weakThis, pc, cc, n] - { - if (weakThis != nullptr && onValueTreeChildRemoved) - onValueTreeChildRemoved (pc, cc, n); - }); - } - - void valueTreeChildOrderChanged (ValueTree& v, int a, int b) override - { - ValueTree vc = v; - WeakReference weakThis (this); - MessageManager::getInstance()->callAsync ([this, weakThis, vc, a, b] - { - if (weakThis != nullptr && onValueTreeChildOrderChanged) - onValueTreeChildOrderChanged (vc, a, b); - }); - } - - void valueTreeParentChanged (ValueTree& v) override - { - ValueTree vc = v; - WeakReference weakThis (this); - MessageManager::getInstance()->callAsync ([this, weakThis, vc] - { - if (weakThis != nullptr && onValueTreeParentChanged) - onValueTreeParentChanged (vc); - }); - } - - void valueTreeRedirected (ValueTree& v) override - { - ValueTree vc = v; - WeakReference weakThis (this); - MessageManager::getInstance()->callAsync ([this, weakThis, vc] - { - if (weakThis != nullptr && onValueTreeRedirected) - onValueTreeRedirected (vc); - }); - } - - ValueTree& vt; - - JUCE_DECLARE_WEAK_REFERENCEABLE (AsyncLambdaValueTreeListener) -};