Passed
Push — dev ( e9cf15...64faf7 )
by Fike
03:26
created

FXAAProcessor::process()   C

Complexity

Conditions 11
Paths 15

Size

Total Lines 58
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 47
nc 15
nop 2
dl 0
loc 58
rs 6.4179
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace AmaTeam\Image\Projection\Conversion\Processor;
4
5
use AmaTeam\Image\Projection\API\Conversion\ProcessorInterface;
6
use AmaTeam\Image\Projection\API\Image\ImageFactoryInterface;
7
use AmaTeam\Image\Projection\API\SpecificationInterface;
8
use AmaTeam\Image\Projection\API\Tile\TileInterface;
9
use AmaTeam\Image\Projection\Conversion\Processor\FXAA\ColorGrid;
10
use AmaTeam\Image\Projection\Conversion\Processor\FXAA\EdgeLumaCalculator;
11
use AmaTeam\Image\Projection\Conversion\Processor\FXAA\EdgeOrientationCalculator;
12
use AmaTeam\Image\Projection\Conversion\Processor\FXAA\EdgeDistanceCalculator;
13
use AmaTeam\Image\Projection\Conversion\Processor\FXAA\Edge;
14
use AmaTeam\Image\Projection\Conversion\Processor\FXAA\EdgeDirectionCalculator;
15
use AmaTeam\Image\Projection\Conversion\Processor\FXAA\LumaGrid;
16
use AmaTeam\Image\Projection\Conversion\Processor\FXAA\SubPixelOffsetCalculator;
17
use AmaTeam\Image\Projection\Conversion\Processor\FXAA\TargetColorCalculator;
18
use AmaTeam\Image\Projection\Image\Utility\Color;
19
use AmaTeam\Image\Projection\Tile\Tile;
20
21
/**
22
 * @see https://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf
23
 * @see http://blog.simonrodriguez.fr/articles/30-07-2016_implementing_fxaa.html
24
 */
25
class FXAAProcessor implements ProcessorInterface
26
{
27
    const DEBUG_OFF = 0;
28
    const DEBUG_EDGE = 1;
29
    // Horizontal edges are
30
    const DEBUG_ORIENTATION = 2;
31
    // Edge is painted in blue, it's contrast opposite - in green
32
    const DEBUG_PAIR = 3;
33
34
    const EDGE_THRESHOLD_TOO_LITTLE = 1 / 3;
35
    const EDGE_THRESHOLD_LOW_QUALITY = 1 / 4;
36
    const EDGE_THRESHOLD_HIGH_QUALITY = 1 / 8;
37
    const EDGE_THRESHOLD_OVERKILL = 1 / 16;
38
39
    const MINIMUM_EDGE_THRESHOLD_VISIBLE_LIMIT = 1 / 32;
40
    const MINIMUM_EDGE_THRESHOLD_HIGH_QUALITY = 1 / 16;
41
    const MINIMUM_EDGE_THRESHOLD_UPPER_LIMIT = 1 / 12;
42
43
    private $edgeThreshold = self::EDGE_THRESHOLD_LOW_QUALITY;
44
    private $minimumEdgeThreshold = self::MINIMUM_EDGE_THRESHOLD_HIGH_QUALITY;
45
    private $debug = self::DEBUG_OFF;
46
47
    /**
48
     * @var ImageFactoryInterface
49
     */
50
    private $imageFactory;
51
52
    /**
53
     * @param ImageFactoryInterface $imageFactory
54
     */
55
    public function __construct(ImageFactoryInterface $imageFactory)
56
    {
57
        $this->imageFactory = $imageFactory;
58
    }
59
60
    /**
61
     * @return float|int
62
     */
63
    public function getEdgeThreshold()
64
    {
65
        return $this->edgeThreshold;
66
    }
67
68
    /**
69
     * @param float|int $edgeThreshold
70
     * @return $this
71
     */
72
    public function setEdgeThreshold($edgeThreshold)
73
    {
74
        $this->edgeThreshold = $edgeThreshold;
75
        return $this;
76
    }
77
78
    /**
79
     * @return float|int
80
     */
81
    public function getMinimumEdgeThreshold()
82
    {
83
        return $this->minimumEdgeThreshold;
84
    }
85
86
    /**
87
     * @param float|int $minimumEdgeThreshold
88
     * @return $this
89
     */
90
    public function setMinimumEdgeThreshold($minimumEdgeThreshold)
91
    {
92
        $this->minimumEdgeThreshold = $minimumEdgeThreshold;
93
        return $this;
94
    }
95
96
    /**
97
     * @inheritDoc
98
     *
99
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
100
     */
101
    public function process(TileInterface $tile, SpecificationInterface $specification)
102
    {
103
        $image = $tile->getImage();
104
        $width = $image->getWidth();
105
        $height = $image->getHeight();
106
        $colorGrid = new ColorGrid();
107
        $lumaGrid = new LumaGrid();
108
        $target = $this->imageFactory->create($width, $height);
109
        $edge = new Edge();
110
        $edge->image = $image;
111
        $edge->color = $colorGrid;
112
        $edge->luma = $lumaGrid;
113
        for ($x = 0; $x < $width; $x++) {
114
            for ($y = 0; $y < $height; $y++) {
115
                $edge->x = $x;
116
                $edge->y = $y;
117
118
                // Gathering 3x3 grid data
119
                $colorGrid->fill($image, $x, $y);
120
                $lumaGrid->fill($colorGrid);
121
122
                // High luma range tells there is an edge in 3x3 box
123
                if ($lumaGrid->range < max($lumaGrid->max * $this->edgeThreshold, $this->minimumEdgeThreshold)) {
124
                    // So if there's no such thing, let's just jump to next pixel
125
                    $target->setColorAt($x, $y, $colorGrid->center);
126
                    continue;
127
                }
128
                EdgeOrientationCalculator::apply($edge);
129
                EdgeDirectionCalculator::apply($edge);
130
                EdgeLumaCalculator::apply($edge);
131
                EdgeDistanceCalculator::apply($edge);
132
                $offset = SubPixelOffsetCalculator::calculate($edge);
133
                switch ($this->debug) {
134
                    case self::DEBUG_EDGE:
135
                        $alpha = (int) ($offset * 2 * 255);
136
                        $yellow = 0xFFFF00FF;
137
                        $yellow = $yellow & ($alpha | 0xFFFFFF00);
138
                        $color = Color::blend(0xFF0000FF, $yellow);
139
                        $target->setColorAt($x, $y, $color);
140
                        break;
141
                    case self::DEBUG_ORIENTATION:
142
                        $color = $edge->horizontal ? 0xFFFF00FF : 0x0000FFFF;
143
                        $target->setColorAt($x, $y, $color);
144
                        break;
145
                    case self::DEBUG_PAIR:
146
                        $target->setColorAt($x, $y, 0x0000FFFF);
147
                        $value = $edge->inward ? -1 : 1;
148
                        $xOffset = $edge->horizontal ? 0 : $value;
149
                        $yOffset = $edge->horizontal ? $value : 0;
150
                        $target->setColorAt($x + $xOffset, $y + $yOffset, 0x00FF00FF);
151
                        break;
152
                    default:
153
                        $color = TargetColorCalculator::calculate($edge, $offset);
154
                        $target->setColorAt($x, $y, $color);
155
                }
156
            }
157
        }
158
        return new Tile($tile->getPosition(), $target);
159
    }
160
161
    public function setDebugMode($mode)
162
    {
163
        $this->debug = $mode;
164
        return $this;
165
    }
166
}
167