Passed
Pull Request — master (#7)
by Mattia
09:16 queued 04:24
created

BaseSkinSection::copyComponent()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 29
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 25
c 1
b 0
f 1
dl 0
loc 29
rs 9.52
cc 3
nc 2
nop 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Minepic\Image\Sections;
6
7
use Minepic\Image\Components\Component;
8
use Minepic\Image\Exceptions\ImageResourceCreationFailedException;
9
use Minepic\Image\ImageSection;
10
use Minepic\Image\LayerValidator;
11
use Minepic\Image\Point;
12
13
abstract class BaseSkinSection extends ImageSection
14
{
15
    protected string $side;
16
    protected int $baseImageWidth = 16;
17
    protected int $baseImageHeight = 32;
18
19
    /**
20
     * @param int $skinHeight
21
     * @throws ImageResourceCreationFailedException
22
     * @throws \Exception
23
     */
24
    public function render(int $skinHeight = 256): void
25
    {
26
        $skinHeight = $this->checkHeight($skinHeight);
27
28
        $tmpImageResource = $this->emptyBaseImage($this->baseImageWidth, $this->baseImageHeight);
29
        foreach ($this->getAllComponents() as $componentName => $componentsData) {
30
            $this->copyComponent($tmpImageResource, $componentName, $componentsData[0], $componentsData[1] ?? null);
31
        }
32
33
        $this->patchOldSkin($tmpImageResource);
34
35
        $scale = $skinHeight / $this->baseImageHeight;
36
        if ($scale === 0) {
37
            $scale = 1;
38
        }
39
        $skinWidth = (int) \round($scale * ($this->baseImageWidth));
40
41
        $this->imgResource = $this->emptyBaseImage($skinWidth, $skinHeight);
42
        \imagecopyresized($this->imgResource, $tmpImageResource, 0, 0, 0, 0, $skinWidth, $skinHeight, $this->baseImageWidth, $this->baseImageHeight);
43
    }
44
45
    /**
46
     * @return Point[]
47
     */
48
    abstract protected function startingPoints(): array;
49
50
    /**
51
     * In old skins (pre 1.8) left arm/leg are right arm/leg flipped
52
     * @param $tmpImageResource
53
     * @throws \Exception
54
     */
55
    protected function patchOldSkin($tmpImageResource): void
56
    {
57
        if ($this->is64x64()) {
58
            return;
59
        }
60
61
        if (\array_key_exists(Component::LEFT_ARM, $this->startingPoints())) {
62
            $this->flipComponent(
63
                $tmpImageResource,
64
                Component::getLeftArm(),
65
                Component::getRightArm(),
66
                $this->startingPoints()[Component::LEFT_ARM]
67
            );
68
        }
69
70
        if (\array_key_exists(Component::LEFT_LEG, $this->startingPoints())) {
71
            $this->flipComponent(
72
                $tmpImageResource,
73
                Component::getLeftLeg(),
74
                Component::getRightLeg(),
75
                $this->startingPoints()[Component::LEFT_LEG]
76
            );
77
        }
78
    }
79
80
    /**
81
     * @param $tmpImageResource
82
     * @param Component $dstComponent
83
     * @param Component $srcComponent
84
     * @param Point $startingPoint
85
     * @throws \Exception
86
     */
87
    protected function flipComponent($tmpImageResource, Component $dstComponent, Component $srcComponent, Point $startingPoint): void
88
    {
89
        $leftArmData = $dstComponent->getSideByIdentifier($this->side);
90
        $rightArmData = $srcComponent->getSideByIdentifier($this->side);
91
        $width = $leftArmData->getWidth();
92
        $height = $leftArmData->getHeight();
93
        $leftArm = \imagecreatetruecolor($width, $height);
94
        for ($x = 0; $x < 4; ++$x) {
95
            \imagecopy($leftArm,
96
                $this->skinResource,
97
                $x,
98
                0,
99
                $rightArmData->getBottomRight()->getX() - $x - 1,
100
                $rightArmData->getTopLeft()->getY(),
101
                1,
102
                $height
103
            );
104
        }
105
        \imagecopymerge($tmpImageResource,
106
            $leftArm,
107
            $startingPoint->getX(),
108
            $startingPoint->getY(),
109
            0,
110
            0,
111
            $width,
112
            $height,
113
        100
114
        );
115
    }
116
117
    /**
118
     * @param $skinHeight
119
     *
120
     * @return int
121
     */
122
    protected function checkHeight($skinHeight): int
123
    {
124
        if ($skinHeight === 0 || $skinHeight < 0 || $skinHeight > (int) env('MAX_SKINS_SIZE')) {
125
            $skinHeight = (int) env('DEFAULT_SKIN_SIZE');
126
        }
127
128
        return $skinHeight;
129
    }
130
131
    /**
132
     * @return array[]
133
     */
134
    protected function getAllComponents(): array
135
    {
136
        if ($this->is64x64()) {
137
            return [
138
                Component::HEAD => [Component::getHead(), Component::getHeadLayer()],
139
                Component::TORSO => [Component::getTorso(), Component::getTorsoLayer()],
140
                Component::RIGHT_ARM => [Component::getRightArm(), Component::getRightArmLayer()],
141
                Component::LEFT_ARM => [Component::getLeftArm(), Component::getLeftArmLayer()],
142
                Component::RIGHT_LEG => [Component::getRightLeg(), Component::getRightLegLayer()],
143
                Component::LEFT_LEG => [Component::getLeftLeg(), Component::getLeftLegLayer()],
144
            ];
145
        }
146
147
        return [
148
            Component::HEAD => [Component::getHead(), Component::getHeadLayer()],
149
            Component::TORSO => [Component::getTorso()],
150
            Component::RIGHT_ARM => [Component::getRightArm()],
151
            Component::RIGHT_LEG => [Component::getRightLeg()],
152
        ];
153
    }
154
155
    /**
156
     * @param $tmpImageResource
157
     * @param string $componentName
158
     * @param Component $base
159
     * @param null|Component $layer
160
     * @throws \Exception
161
     */
162
    protected function copyComponent($tmpImageResource, string $componentName, Component $base, ?Component $layer): void
163
    {
164
        $sideBase = $base->getSideByIdentifier($this->side);
165
        $width = $sideBase->getWidth();
166
        $height = $sideBase->getHeight();
167
168
        $startingPoint = $this->startingPoints()[$componentName] ?? new Point(0, 0);
169
        \imagecopy(
170
            $tmpImageResource,
171
            $this->skinResource,
172
            $startingPoint->getX(),
173
            $startingPoint->getY(),
174
            $sideBase->getTopLeft()->getX(),
175
            $sideBase->getTopLeft()->getY(),
176
            $width,
177
            $height
178
        );
179
        if ($layer !== null && (new LayerValidator())->check($this->skinResource, $layer->getSideByIdentifier($this->side))) {
180
            $sideLayer = $layer->getSideByIdentifier($this->side);
181
            \imagecopymerge_alpha(
182
                $tmpImageResource,
183
                $this->skinResource,
184
                $startingPoint->getX(),
185
                $startingPoint->getY(),
186
                $sideLayer->getTopLeft()->getX(),
187
                $sideLayer->getTopLeft()->getY(),
188
                $width,
189
                $height,
190
                100
191
            );
192
        }
193
    }
194
}
195