BaseSkinSection::getAllComponents()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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