Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
141 | dmarschall | 1 | |
2 | Implementation detail differences Daniel Marschall |
||
158 | dmarschall | 3 | ================================= 08 January 2018 |
141 | dmarschall | 4 | |
144 | dmarschall | 5 | FilterFoundry tries to be as compatible with Filter Factory as possible. |
192 | daniel-mar | 6 | However, results are usually not 100% equal because functions like |
7 | cos, sin, sqr, etc., have different accuracy due to the underlying |
||
141 | dmarschall | 8 | implementation. |
9 | |||
192 | daniel-mar | 10 | Furthermore, there are the following known differences between |
11 | Filter Foundry and Filter Factory: |
||
141 | dmarschall | 12 | |
158 | dmarschall | 13 | i, u, v (Testcase iuv.afs) |
141 | dmarschall | 14 | ------- |
15 | |||
16 | Filter Foundry <1.7 uses the same formulas as in Filter Factory: |
||
17 | |||
18 | i=((76*r)+(150*g)+(29*b))/256 Output range is 0..254 |
||
146 | dmarschall | 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 |
||
141 | dmarschall | 21 | |
22 | Filter Foundry 1.7 uses more accurate formulas: |
||
23 | |||
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 |
||
26 | v=614777*r-514799*g-99978*b)/2000000 Output range is -78..78 |
||
27 | |||
192 | daniel-mar | 28 | Both formulas follow the same YUV standard but have different accuracy. |
141 | dmarschall | 29 | |
30 | |||
31 | get(i) (Testcase getput.afs) |
||
32 | ------ |
||
33 | |||
34 | Filter Foundry: |
||
35 | get(x)=0 if x>255 or x<0 |
||
36 | |||
37 | Filter Factory: |
||
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] |
||
40 | |||
41 | |||
42 | r, g, b at empty canvas (Testcase emptycanvas.afs) |
||
43 | ----------------------- |
||
44 | |||
45 | In Filter Factory, an empty (transparent) canvas of a new file is initialized as r=g=b=0 |
||
46 | |||
47 | Filter Foundry initializes it as r=g=b=255 |
||
48 | |||
49 | |||
50 | rnd(a,b) and rst(i) (Testcases rst_*.afs) |
||
51 | ------------------- |
||
52 | |||
192 | daniel-mar | 53 | Filter Foundry's implementation of rst(i) (an undocumented function that sets the seed for the PRG) |
54 | and rnd(a,b) (generate a random number between a and b, inclusively) |
||
144 | dmarschall | 55 | differs from the implementation of Filter Factory in many ways. |
141 | dmarschall | 56 | |
144 | dmarschall | 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. |
||
141 | dmarschall | 59 | |
144 | dmarschall | 60 | 2. In Filter Foundry, the argument i of the function rst(i) is limited to the |
141 | dmarschall | 61 | type "unsigned int" (argument of the function srand() in the C StdLib), |
62 | so the allowed range is 0..4294967295. |
||
63 | |||
64 | In Filter Factory, the argument i must be between 0 and 32767, inclusively. |
||
142 | dmarschall | 65 | If the argument is not within this range, the operation "and 0x7FFF" will be applied to it |
141 | dmarschall | 66 | to extract the low 15 bits. |
143 | dmarschall | 67 | |
192 | daniel-mar | 68 | 3. In Filter Foundry, the function rnd(a,b) retrieves a random number in realtime; therefore, if the |
144 | dmarschall | 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: |
||
71 | R: rst(123), rnd(0,255) |
||
72 | G: 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 |
||
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) |
||
77 | G: rnd(0,255) |
||
78 | B: rnd(0,255) |
||
143 | dmarschall | 79 | |
144 | dmarschall | 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. |
||
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: |
||
84 | R: rst(123), rnd(0,255) |
||
85 | G: rnd(0,255) |
||
86 | B: rnd(0,255) |
||
87 | Following filter would generate a different random pixel picture: |
||
88 | R: rst(456), rnd(0,255) |
||
89 | G: rnd(0,255) |
||
90 | B: rnd(0,255) |
||
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 |
||
93 | G: rnd(0,255) |
||
94 | B: rnd(0,255)+rst(456) <-- the last rst(456) call is to mitigate a bug; see below. |
||
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: |
||
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. |
||
99 | Example: |
||
100 | R: rnd(0,255), rst(123) <-- note that the rst(123) is ignored because rnd() was already called. |
||
101 | G: rnd(0,255) |
||
102 | B: rnd(0,255) |
||
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). |
||
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. |
||
107 | |||
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: |
||
110 | R: rst(333), rnd(0,255) |
||
111 | G: rnd(0,255) |
||
112 | B: rnd(0,255)+rst(555) |
||
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. |
||
115 | Another example: |
||
116 | R: rst(ctl(0)), rnd(0,255) |
||
117 | G: rnd(0,255) |
||
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. |
||
120 | |||
121 | |||
143 | dmarschall | 122 | Evaluation of conditional branches |
123 | ---------------------------------- |
||
124 | |||
144 | dmarschall | 125 | Filter Foundry: |
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) |
||
128 | R: 1==0 ? put(255,0) : 0 |
||
129 | G: get(0) |
||
130 | B: 0 |
||
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) |
||
133 | R: 1==0 && put(255,0) ? 0: 0 |
||
134 | G: get(0) |
||
135 | B: 0 |
||
136 | This will also generate a black canvas: (Testcase conditional_eval_3.afs) |
||
137 | R: 1==1 || put(255,0) ? 0 : 0 |
||
138 | G: get(0) |
||
139 | B: 0 |
||
140 | |||
143 | dmarschall | 141 | Filter Factory: |
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) |
||
144 | dmarschall | 144 | R: 1==0 ? put(255,0) : 0 |
145 | G: get(0) |
||
146 | B: 0 |
||
143 | dmarschall | 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) |
||
144 | dmarschall | 149 | R: 1==0 && put(255,0) ? 0: 0 |
150 | G: get(0) |
||
151 | B: 0 |
||
152 | This will also generate a green canvas: (Testcase conditional_eval_3.afs) |
||
153 | R: 1==1 || put(255,0) ? 0 : 0 |
||
154 | G: get(0) |
||
155 | B: 0 |