Subversion Repositories filter_foundry

Rev

Rev 297 | Rev 335 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
141 dmarschall 1
 
294 daniel-mar 2
 
221 daniel-mar 3
Implementation detail differences
4
=================================
141 dmarschall 5
 
304 daniel-mar 6
Filter Foundry tries to be as compatible with Filter Factory as possible.
7
However, there are some differences that are explained in this documentation.
141 dmarschall 8
 
294 daniel-mar 9
Various implementations
10
-----------------------
141 dmarschall 11
 
294 daniel-mar 12
In the source-code file funcs.c, some functions are implemented twice:
13
One instance is the default implementation (older Filter Foundry versions used),
14
and one instance is a 100% replica of the Filter Factory code, obtained
15
from the "OPER" resource.
16
(More information at https://misc.daniel-marschall.de/projects/filter_factory/res_oper.html )
297 daniel-mar 17
If required, the compiler-definitions `use_filterfactory_implementation_*`
294 daniel-mar 18
can be set or unset to select the implementation.
19
 
304 daniel-mar 20
In Filter Foundry 1.7.0.8, the following functions have been updated to the Filter Factory replica:
297 daniel-mar 21
- `rnd(x)`
22
- `cos(x)`
23
- `sin(x)`
24
- `tan(x)`
25
- `r2x(d,m)`
26
- `r2y(d,m)`
27
- `rad(d,m,z)`
28
- `c2d(x,y)`
29
- `c2m(x,y)`
30
- `sqr(x)`
31
- `d`
32
- `m`
33
- `M`
294 daniel-mar 34
 
35
 
36
sqr(x)
37
------
38
 
39
Filter Factory:
40
 
41
	sqr(x)=x for x < 0
295 daniel-mar 42
 
304 daniel-mar 43
	Can be tested with the following expression:
295 daniel-mar 44
	sqr(-20)+21 == 1
294 daniel-mar 45
 
46
Filter Foundry (prior to 1.7.0.8):
47
 
48
	sqr(x)=0 for x < 0
49
 
304 daniel-mar 50
Beginning with Filter Foundry 1.7.0.8, the behavior of Filter Factory was implemented.
297 daniel-mar 51
 
304 daniel-mar 52
 
158 dmarschall 53
i, u, v (Testcase iuv.afs)
141 dmarschall 54
-------
55
 
56
Filter Foundry <1.7 uses the same formulas as in Filter Factory:
57
 
221 daniel-mar 58
    i=((76*r)+(150*g)+(29*b))/256            // Output range is 0..254
59
    u=((-19*r)+(-37*g)+(56*b))/256           // Output range is -55..55
60
    v=((78*r)+(-65*g)+(-13*b))/256           // Output range is -77..77
141 dmarschall 61
 
62
Filter Foundry 1.7 uses more accurate formulas:
63
 
221 daniel-mar 64
    i=(299*r+587*g+114*b)/1000               // Output range is 0..255
65
    u=(-147407*r-289391*g+436798*b)/2000000  // Output range is -55..55
66
    v=614777*r-514799*g-99978*b)/2000000     // Output range is -78..78
141 dmarschall 67
 
192 daniel-mar 68
Both formulas follow the same YUV standard but have different accuracy.
141 dmarschall 69
 
70
 
304 daniel-mar 71
I, U, V, imin, umin, vmin (Testcase iuv_minmax.afs)
72
-------------------------
73
 
74
In Filter Foundry 1.7.0.8, the previously undocumented variables I, U, V as well as imin, umin, vmin
75
have been changed to represent the actual results of the i,u,v variables:
76
 
77
    I, imax = 255 (stayed the same)
78
    U, umax = 55 (was 255 in Filter Factory)
79
    V, vmax = 78 (was 255 in Filter Factory)
80
 
81
    imin = 0 (stayed the same)
82
    umin = -55 (was 0 in Filter Factory)
83
    vmin = -78 (was 0 in Filter Factory)
84
 
85
 
141 dmarschall 86
get(i) (Testcase getput.afs)
87
------
88
 
89
Filter Foundry:
90
 
221 daniel-mar 91
    get(x)=0 if x>255 or x<0
92
 
141 dmarschall 93
Filter Factory:
94
 
221 daniel-mar 95
    get(x)=x if x>255 or x<0
141 dmarschall 96
 
221 daniel-mar 97
Note: The result "x" was most likely not intended but a result of an undefined behavior
98
 
99
 
141 dmarschall 100
r, g, b at empty canvas (Testcase emptycanvas.afs)
101
-----------------------
102
 
221 daniel-mar 103
In Filter Factory, an empty (transparent) canvas of a new file is initialized as `r=g=b=0`
141 dmarschall 104
 
221 daniel-mar 105
Filter Foundry initializes it as `r=g=b=255`
141 dmarschall 106
 
107
 
294 daniel-mar 108
rnd(a,b) (Testcases rnd*)
289 daniel-mar 109
--------
110
 
111
Filter Factory uses Donald E. Knuth's subtractive random number generator algorithm,
112
which has been published in "The Art of Computer Programming, volume 2: Seminumerical Algorithms".
113
Addison-Wesley, Reading, MA, second edition, 1981.
114
 
115
Beginning with Filter Foundry 1.7.0.8, the same PRNG was implemented,
116
so that the output of rnd(a,b) is exactly the same now.
117
 
118
 
294 daniel-mar 119
rst(i) (Testcases rnd*.afs and rst_*.afs)
120
------
141 dmarschall 121
 
289 daniel-mar 122
Filter Factory contains an undocumented function that sets the seed for the random number generator.
141 dmarschall 123
 
304 daniel-mar 124
Filter Factory and Filter Foundry beginning with 1.7.0.8 accept a seed between 0 and 32767, inclusively.
125
If the argument is not within this range, the operation lowest 15 bits are taken.
141 dmarschall 126
 
304 daniel-mar 127
There are many differences in the implementation between Filter Factory and Filter Foundry in regards rst(i):
141 dmarschall 128
 
289 daniel-mar 129
**Filter Factory:**
143 dmarschall 130
 
289 daniel-mar 131
If rst(i) is called in Filter Factory, an internal Seed-Variable is set.
132
It does NOT influence any calls of rnd(a,b), because a lookup-table needs to be built first.
133
The building of the lookup-table is probably done before the processing of the first pixel (x,y,z=0).
134
It is suspected that the call of rst(i) will take effect on the next calculation.
135
Due to a bug (or feature?), the random state is not reset to its initial state (0) before the
136
filter is applied. The preview image processing will modify the random state, and once the filter
137
is actually applied (pressing "OK"), the random state that was set in the preview picture, will be used.
138
This could be considered as a bug, but it is probably required, otherwise the call of rst(i)
139
(inside the preview calculation) won't affect the rnd(a,b) in the real run.
140
However, in a standalone filter without dialog/preview, there is no preview that could set
141
the internal seed, so the rnd(a,b) functions will always work using the default seed 0,
142
and only the subsequent calls will use the rst(i) of the previous call.
221 daniel-mar 143
 
289 daniel-mar 144
**Filter Foundry:**
143 dmarschall 145
 
289 daniel-mar 146
In Filter Foundry, the function rnd(a,b) retrieves a random number in "realtime"; therefore, if the
147
seed is changed via rst(i), there is an immediate effect on the next call of the rnd(a,b) function.
148
 
304 daniel-mar 149
For example, the following filter would generate an one-colored picture without any randomness:
221 daniel-mar 150
        R: rst(123), rnd(0,255)
151
        G: rnd(0,255)
152
        B: rnd(0,255)
144 dmarschall 153
 
289 daniel-mar 154
If you want to generate a random pixel image with a non-default seed, you need to make sure
155
that rst(i) is called only once at the beginning (channel 0, coordinate 0|0):
294 daniel-mar 156
        R: (x== 0 && y ==0) ? rst(123) : 0, rnd(0,255)
221 daniel-mar 157
        G: rnd(0,255)
158
        B: rnd(0,255)
144 dmarschall 159
 
289 daniel-mar 160
In Filter Foundry, rst(i) can be called by branches and variables/sliders can
161
be used as arguments of rst(i).
144 dmarschall 162
 
163
 
143 dmarschall 164
Evaluation of conditional branches
165
----------------------------------
166
 
221 daniel-mar 167
**Filter Foundry:**
144 dmarschall 168
 
221 daniel-mar 169
Only the branches which will be chosen due to the conditional expression will be evaluated.
170
 
304 daniel-mar 171
This means that the following filter would generate a black canvas: (Testcase conditional_eval_1.afs)
221 daniel-mar 172
 
173
        R: 1==0 ? put(255,0) : 0
174
        G: get(0)
175
        B: 0
176
 
177
In boolean expressions, the evaluation will be aborted if the result is already determined.
178
 
179
So, this will also generate a black canvas: (Testcase conditional_eval_2.afs)
180
 
181
        R: 1==0 && put(255,0) ? 0: 0
182
        G: get(0)
183
        B: 0
184
 
185
This will also generate a black canvas: (Testcase conditional_eval_3.afs)
186
 
187
        R: 1==1 || put(255,0) ? 0 : 0
188
        G: get(0)
189
        B: 0
190
 
191
**Filter Factory:**
192
 
304 daniel-mar 193
Each branch inside an if-then-else expression will be evaluated.
194
This means that the following filter would generate a green canvas: (Testcase conditional_eval_1.afs)
221 daniel-mar 195
 
196
        R: 1==0 ? put(255,0) : 0
197
        G: get(0)
198
        B: 0
199
 
304 daniel-mar 200
Also, all arguments of a boolean expression will be fully evaluated.
221 daniel-mar 201
So, this will also generate a green canvas: (Testcase conditional_eval_2.afs)
202
 
203
        R: 1==0 && put(255,0) ? 0: 0
204
        G: get(0)
205
        B: 0
206
 
207
This will also generate a green canvas: (Testcase conditional_eval_3.afs)
208
 
209
        R: 1==1 || put(255,0) ? 0 : 0
210
        G: get(0)
211
        B: 0