Subversion Repositories filter_foundry

Rev

Rev 158 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 158 Rev 192
1
 
1
 
2
Implementation detail differences			Daniel Marschall
2
Implementation detail differences			Daniel Marschall
3
=================================			08 January 2018
3
=================================			08 January 2018
4
 
4
 
5
FilterFoundry tries to be as compatible with Filter Factory as possible.
5
FilterFoundry tries to be as compatible with Filter Factory as possible.
6
However, results are usually not 100% equal, because functions like
6
However, results are usually not 100% equal because functions like
7
cos, sin, sqr, etc. have different accuracy due to the underlying
7
cos, sin, sqr, etc., have different accuracy due to the underlying
8
implementation.
8
implementation.
9
 
9
 
10
Furthermore, there are following known differences between Filter Foundry
10
Furthermore, there are the following known differences between
11
and Filter Factory:
11
Filter Foundry and Filter Factory:
12
 
12
 
13
i, u, v (Testcase iuv.afs)
13
i, u, v (Testcase iuv.afs)
14
-------
14
-------
15
 
15
 
16
Filter Foundry <1.7 uses the same formulas as in Filter Factory:
16
Filter Foundry <1.7 uses the same formulas as in Filter Factory:
17
 
17
 
18
	i=((76*r)+(150*g)+(29*b))/256            Output range is 0..254
18
	i=((76*r)+(150*g)+(29*b))/256            Output range is 0..254
19
	u=((-19*r)+(-37*g)+(56*b))/256           Output range is -55..55
19
	u=((-19*r)+(-37*g)+(56*b))/256           Output range is -55..55
20
	v=((78*r)+(-65*g)+(-13*b))/256           Output range is -77..77
20
	v=((78*r)+(-65*g)+(-13*b))/256           Output range is -77..77
21
 
21
 
22
Filter Foundry 1.7 uses more accurate formulas:
22
Filter Foundry 1.7 uses more accurate formulas:
23
 
23
 
24
	i=(299*r+587*g+114*b)/1000               Output range is 0..255
24
	i=(299*r+587*g+114*b)/1000               Output range is 0..255
25
	u=(-147407*r-289391*g+436798*b)/2000000  Output range is -55..55
25
	u=(-147407*r-289391*g+436798*b)/2000000  Output range is -55..55
26
	v=614777*r-514799*g-99978*b)/2000000     Output range is -78..78
26
	v=614777*r-514799*g-99978*b)/2000000     Output range is -78..78
27
 
27
 
28
Both formulas follow the same YUV standard, but have different accuracy.
28
Both formulas follow the same YUV standard but have different accuracy.
29
 
29
 
30
 
30
 
31
get(i) (Testcase getput.afs)
31
get(i) (Testcase getput.afs)
32
------
32
------
33
 
33
 
34
Filter Foundry:
34
Filter Foundry:
35
	get(x)=0 if x>255 or x<0
35
	get(x)=0 if x>255 or x<0
36
 
36
 
37
Filter Factory:
37
Filter Factory:
38
	get(x)=x if x>255 or x<0
38
	get(x)=x if x>255 or x<0
39
	[Note: The result "x" was most likely not intended but a result of an undefined behavior]
39
	[Note: The result "x" was most likely not intended but a result of an undefined behavior]
40
 
40
 
41
 
41
 
42
r, g, b at empty canvas (Testcase emptycanvas.afs)
42
r, g, b at empty canvas (Testcase emptycanvas.afs)
43
-----------------------
43
-----------------------
44
 
44
 
45
In Filter Factory, an empty (transparent) canvas of a new file is initialized as r=g=b=0
45
In Filter Factory, an empty (transparent) canvas of a new file is initialized as r=g=b=0
46
 
46
 
47
Filter Foundry initializes it as r=g=b=255
47
Filter Foundry initializes it as r=g=b=255
48
 
48
 
49
 
49
 
50
rnd(a,b) and rst(i) (Testcases rst_*.afs)
50
rnd(a,b) and rst(i) (Testcases rst_*.afs)
51
-------------------
51
-------------------
52
 
52
 
53
Filter Foundry's implementation of rst(i) (undocumented function that sets the seed for the PRG)
53
Filter Foundry's implementation of rst(i) (an undocumented function that sets the seed for the PRG)
54
and rnd(a,b) (generate random number between a and b, inclusively)
54
and rnd(a,b) (generate a random number between a and b, inclusively)
55
differs from the implementation of Filter Factory in many ways.
55
differs from the implementation of Filter Factory in many ways.
56
 
56
 
57
1. In Filter Foundry, the random seed is automatically initialized with seed 691204.
57
1. In Filter Foundry, the random seed is automatically initialized with seed 691204.
58
   In Filter Factory, the random seed is automatically initialized with seed 0.   
58
   In Filter Factory, the random seed is automatically initialized with seed 0.   
59
 
59
 
60
2. In Filter Foundry, the argument i of the function rst(i) is limited to the
60
2. In Filter Foundry, the argument i of the function rst(i) is limited to the
61
   type "unsigned int" (argument of the function srand() in the C StdLib),
61
   type "unsigned int" (argument of the function srand() in the C StdLib),
62
   so the allowed range is 0..4294967295.
62
   so the allowed range is 0..4294967295.
63
 
63
 
64
   In Filter Factory, the argument i must be between 0 and 32767, inclusively.
64
   In Filter Factory, the argument i must be between 0 and 32767, inclusively.
65
   If the argument is not within this range, the operation "and 0x7FFF" will be applied to it
65
   If the argument is not within this range, the operation "and 0x7FFF" will be applied to it
66
   to extract the low 15 bits.
66
   to extract the low 15 bits.
67
 
67
 
68
3. In Filter Foundry, the function rnd(a,b) retrieves a random number at realtime; therefore, if the
68
3. In Filter Foundry, the function rnd(a,b) retrieves a random number in realtime; therefore, if the
69
   seed is changed via rst(i), there is an immediate effect on the next call of the rnd(a,b) function.
69
   seed is changed via rst(i), there is an immediate effect on the next call of the rnd(a,b) function.
70
   For example, following filter would generate an one-colored picture without any randomness:
70
   For example, following filter would generate an one-colored picture without any randomness:
71
	R: rst(123), rnd(0,255)
71
	R: rst(123), rnd(0,255)
72
	G: rnd(0,255)
72
	G: rnd(0,255)
73
	B: rnd(0,255)
73
	B: rnd(0,255)
74
   If you want to generate a random pixel image with a non-default seed, you need to make sure
74
   If you want to generate a random pixel image with a non-default seed, you need to make sure
75
   that rst(i) is called only once at the beginning (channel 0, coordinate 0|0):
75
   that rst(i) is called only once at the beginning (channel 0, coordinate 0|0):
76
	R: (x==0 && y==0) ? rst(123) : 0, rnd(0,255)
76
	R: (x==0 && y==0) ? rst(123) : 0, rnd(0,255)
77
	G: rnd(0,255)
77
	G: rnd(0,255)
78
	B: rnd(0,255)
78
	B: rnd(0,255)
79
 
79
 
80
   In Filter Factory, the rnd(a,b) function is more complex.
80
   In Filter Factory, the rnd(a,b) function is more complex.
81
   As soon as the function rnd(a,b) is used once, rst(i) will not have any effect.
81
   As soon as the function rnd(a,b) is used once, rst(i) will not have any effect.
82
   So, if you want to use rst(i), you must make sure to call it before using rnd(a,b).
82
   So, if you want to use rst(i), you must make sure to call it before using rnd(a,b).
83
   Following filter will generate a random pixel picture:
83
   Following filter will generate a random pixel picture:
84
	R: rst(123), rnd(0,255)
84
	R: rst(123), rnd(0,255)
85
	G: rnd(0,255)
85
	G: rnd(0,255)
86
	B: rnd(0,255)
86
	B: rnd(0,255)
87
   Following filter would generate a different random pixel picture:
87
   Following filter would generate a different random pixel picture:
88
	R: rst(456), rnd(0,255)
88
	R: rst(456), rnd(0,255)
89
	G: rnd(0,255)
89
	G: rnd(0,255)
90
	B: rnd(0,255)
90
	B: rnd(0,255)
91
   Following filter would generate the same random pixel picture:
91
   Following filter would generate the same random pixel picture:
92
	R: rst(456), rnd(0,255)+rst(123)  <-- note that rst() always returns 0, so the '+' operator is OK
92
	R: rst(456), rnd(0,255)+rst(123)  <-- note that rst() always returns 0, so the '+' operator is OK
93
	G: rnd(0,255)
93
	G: rnd(0,255)
94
	B: rnd(0,255)+rst(456)            <-- the last rst(456) call is to mitigate a bug; see below.
94
	B: rnd(0,255)+rst(456)            <-- the last rst(456) call is to mitigate a bug; see below.
95
 
95
 
96
4. In Filter Factory, due to a bug, the random state is not reset to its initial state (0) before the filter is applied:
96
4. In Filter Factory, due to a bug, the random state is not reset to its initial state (0) before the filter is applied:
97
   The preview image processing will modify the random state, and once the filter is actually applied (pressing "OK"),
97
   The preview image processing will modify the random state, and once the filter is actually applied (pressing "OK"),
98
   the random state that was set in the preview picture, will be used.
98
   the random state that was set in the preview picture, will be used.
99
   Example:
99
   Example:
100
	R: rnd(0,255), rst(123)    <-- note that the rst(123) is ignored because rnd() was already called.
100
	R: rnd(0,255), rst(123)    <-- note that the rst(123) is ignored because rnd() was already called.
101
	G: rnd(0,255)
101
	G: rnd(0,255)
102
	B: rnd(0,255)
102
	B: rnd(0,255)
103
   This filter will produce a random pixel picture with the initial default random seed 0,
103
   This filter will produce a random pixel picture with the initial default random seed 0,
104
   but only for the first calculation (i.e. in the preview picture processing, or in a standalone filter without dialog).
104
   but only for the first calculation (i.e. in the preview picture processing, or in a standalone filter without dialog).
105
   Any further calculation will result in a random pixel picture with random seed 123,
105
   Any further calculation will result in a random pixel picture with random seed 123,
106
   since the random seed 123 will be taken from the previous run.
106
   since the random seed 123 will be taken from the previous run.
107
 
107
 
108
   Furthermore, the random state can't be changed again, not even at the beginning of the red channel before any rnd() call.
108
   Furthermore, the random state can't be changed again, not even at the beginning of the red channel before any rnd() call.
109
   Example:
109
   Example:
110
	R: rst(333), rnd(0,255)
110
	R: rst(333), rnd(0,255)
111
	G: rnd(0,255)
111
	G: rnd(0,255)
112
	B: rnd(0,255)+rst(555)
112
	B: rnd(0,255)+rst(555)
113
   This filter will produce a picture with random seed 333 on the first calculation,
113
   This filter will produce a picture with random seed 333 on the first calculation,
114
   and at every further calculation, a random picture with seed 555.
114
   and at every further calculation, a random picture with seed 555.
115
   Another example:
115
   Another example:
116
	R: rst(ctl(0)), rnd(0,255)
116
	R: rst(ctl(0)), rnd(0,255)
117
	G: rnd(0,255)
117
	G: rnd(0,255)
118
	B: rnd(0,255)+rst(555)
118
	B: rnd(0,255)+rst(555)
119
   In this filter, the slider value is ignored and the resulting picture will always be the same.
119
   In this filter, the slider value is ignored and the resulting picture will always be the same.
120
 
120
 
121
 
121
 
122
Evaluation of conditional branches
122
Evaluation of conditional branches
123
----------------------------------
123
----------------------------------
124
 
124
 
125
Filter Foundry:
125
Filter Foundry:
126
	Only the branches which will be chosen due to the conditional expression will be evaluated.
126
	Only the branches which will be chosen due to the conditional expression will be evaluated.
127
	This means that following filter would generate a black canvas: (Testcase conditional_eval_1.afs)
127
	This means that following filter would generate a black canvas: (Testcase conditional_eval_1.afs)
128
	R: 1==0 ? put(255,0) : 0
128
	R: 1==0 ? put(255,0) : 0
129
	G: get(0)
129
	G: get(0)
130
	B: 0
130
	B: 0
131
	In boolean expressions, the evaluation will be aborted if the result is already determined.
131
	In boolean expressions, the evaluation will be aborted if the result is already determined.
132
	So, this will also generate a black canvas: (Testcase conditional_eval_2.afs)
132
	So, this will also generate a black canvas: (Testcase conditional_eval_2.afs)
133
	R: 1==0 && put(255,0) ? 0: 0
133
	R: 1==0 && put(255,0) ? 0: 0
134
	G: get(0)
134
	G: get(0)
135
	B: 0
135
	B: 0
136
	This will also generate a black canvas: (Testcase conditional_eval_3.afs)
136
	This will also generate a black canvas: (Testcase conditional_eval_3.afs)
137
	R: 1==1 || put(255,0) ? 0 : 0
137
	R: 1==1 || put(255,0) ? 0 : 0
138
	G: get(0)
138
	G: get(0)
139
	B: 0
139
	B: 0
140
 
140
 
141
Filter Factory:
141
Filter Factory:
142
	Each branch inside a if-then-else expression will be evaluated.
142
	Each branch inside a if-then-else expression will be evaluated.
143
	This means that following filter would generate a green canvas: (Testcase conditional_eval_1.afs)
143
	This means that following filter would generate a green canvas: (Testcase conditional_eval_1.afs)
144
	R: 1==0 ? put(255,0) : 0
144
	R: 1==0 ? put(255,0) : 0
145
	G: get(0)
145
	G: get(0)
146
	B: 0
146
	B: 0
147
	Also, all arguments of an boolean expression will be fully evaluated.
147
	Also, all arguments of an boolean expression will be fully evaluated.
148
	So, this will also generate a green canvas: (Testcase conditional_eval_2.afs)
148
	So, this will also generate a green canvas: (Testcase conditional_eval_2.afs)
149
	R: 1==0 && put(255,0) ? 0: 0
149
	R: 1==0 && put(255,0) ? 0: 0
150
	G: get(0)
150
	G: get(0)
151
	B: 0
151
	B: 0
152
	This will also generate a green canvas: (Testcase conditional_eval_3.afs)
152
	This will also generate a green canvas: (Testcase conditional_eval_3.afs)
153
	R: 1==1 || put(255,0) ? 0 : 0
153
	R: 1==1 || put(255,0) ? 0 : 0
154
	G: get(0)
154
	G: get(0)
155
	B: 0
155
	B: 0