Subversion Repositories filter_foundry

Rev

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