Rev 142 | Rev 144 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
141 | dmarschall | 1 | |
2 | Implementation detail differences Daniel Marschall |
||
143 | dmarschall | 3 | ================================= 03 January 2018 |
141 | dmarschall | 4 | |
5 | FilterFoundry tries to be as compatible with FilterFactory as possible. |
||
6 | However, results are usually not 100% equal, because functions like |
||
7 | cos, sin, sqr, etc. have different accuracy due to the underlying |
||
8 | implementation. |
||
9 | |||
10 | Furthermore, there are following known differences between Filter Foundry |
||
11 | and Filter Factory: |
||
12 | |||
13 | i, u, v |
||
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 |
||
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 |
||
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 | |||
28 | Both formulas follow the same YUV standard, but have different accuracy. |
||
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 | |||
53 | Filter Foundry's implementation of rst(i) (undocumented function that sets the seed for the PRG) |
||
54 | differs from the implementation of Filter Factory. |
||
55 | |||
56 | 1. In Filter Foundry, the function rnd(a,b) retrieves a random number at realtime; therefore, if the |
||
57 | seed is changed via rst(i), there is an immediate effect on the next call of the rnd(a,b) function. |
||
58 | For example, following filter would generate an one-colored picture without any randomness: |
||
59 | R=rst(123), rnd(0,255) |
||
60 | G=rnd(0,255) |
||
61 | B=rnd(0,255) |
||
62 | |||
63 | In Filter Factory, the rnd(a,b) function is more complex. |
||
64 | (The analysis of Filter Factory's rnd and rst function is not yet completed, so |
||
65 | following notes might not be 100% accurate.) |
||
66 | It seems like there is a buffer with 56 random integers that will be refilled regularly. |
||
67 | The rst(i) function seems to change the seed for the next batch of random numbers, |
||
68 | so there is not immediate effect on the rnd() calls. |
||
69 | |||
70 | 2. Furthermore, it seems like in Filter Factory, if rst(i) is called multiple times |
||
71 | with the same argument, there will be no effect. |
||
72 | So, while following filter would generate random vertical bars in Filter Foundry, |
||
73 | it would generate a picture with random pixels in Filter Factory: |
||
74 | R=(x==0) ? rst(123) : 0, rnd(0,255) |
||
75 | G=0 |
||
76 | B=0 |
||
77 | |||
78 | In Filter Foundry, every call of rst(i) will perform an update of the seed. |
||
79 | So, if you like to have a random-pixel picture with a specific seed, |
||
80 | you must make sure that rst(i) will only be called once. |
||
81 | You would need to write your filter like this |
||
82 | R=(x==0 && y==0) ? rst(123) : 0, rnd(0,255) |
||
83 | G=0 |
||
84 | B=0 |
||
85 | if you want generate a similar result as Filter Factory outputs with the filter |
||
86 | R=rst(123), rnd(0,255) |
||
87 | G=0 |
||
88 | B=0 |
||
89 | |||
90 | 3. In Filter Foundry, the argument i of the function rst(i) is limited to the |
||
91 | type "unsigned int" (argument of the function srand() in the C StdLib), |
||
92 | so the allowed range is 0..4294967295. |
||
93 | |||
94 | In Filter Factory, the argument i must be between 0 and 32767, inclusively. |
||
142 | dmarschall | 95 | If the argument is not within this range, the operation "and 0x7FFF" will be applied to it |
141 | dmarschall | 96 | to extract the low 15 bits. |
143 | dmarschall | 97 | |
98 | |||
99 | Evaluation of conditional branches |
||
100 | ---------------------------------- |
||
101 | |||
102 | Filter Factory: |
||
103 | Each branch inside a if-then-else expression will be evaluated. |
||
104 | This means that following filter would generate a green canvas: (Testcase conditional_eval_1.afs) |
||
105 | R : 1==0 ? put(255,0) : 0 |
||
106 | G : get(0) |
||
107 | B : 0 |
||
108 | A : 255 |
||
109 | Also, all arguments of an boolean expression will be fully evaluated. |
||
110 | So, this will also generate a green canvas: (Testcase conditional_eval_2.afs) |
||
111 | R : 1==0 && put(255,0) ? 0: 0 |
||
112 | G : get(0) |
||
113 | B : 0 |
||
114 | A : 255 |
||
115 | |||
116 | |||
117 | Filter Foundry: |
||
118 | Only the branches which will be chosen due to the conditional expression will be evaluated. |
||
119 | This means that following filter would generate a black canvas: (Testcase conditional_eval_1.afs) |
||
120 | R : 1==0 ? put(255,0) : 0 |
||
121 | G : get(0) |
||
122 | B : 0 |
||
123 | A : 255 |
||
124 | In boolean expressions, the evaluation will be aborted if the result is already determined. |
||
125 | So, this will also generate a black canvas: (Testcase conditional_eval_2.afs) |
||
126 | R : 1==0 && put(255,0) ? 0: 0 |
||
127 | G : get(0) |
||
128 | B : 0 |
||
129 | A : 255 |