├── char.png
├── README.md
└── 3d.php
/char.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Gyzie/php-Minecraft-3D-Skin-Renderer/HEAD/char.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | php Minecraft 3D Skin Renderer
2 | =====================
3 |
4 | Render a 3D view of a Minecraft skin using PHP.
5 |
6 | Project first developed by supermamie. Later transalated to English by cajogos.
7 | My goal was to fix some issues and hopefully create full support for the 1.8 skins (1.8 support is partly done).
8 |
9 | *I'm no longer working on this project. I will however look into your pull-requests.*
10 |
11 | ### Example of URL:
12 | The URL containing most of the options:
13 | `http://example.com/3d.php?vr=-25&hr=-25&hrh=10&vrla=5&vrra=-2&vrll=-20&vrrl=2&ratio=12&format=png&displayHair=true&headOnly=false&user=Notch`
14 | Note: The old parameters by supermamie will still work.
15 |
16 | With less parameters:
17 | `http://example.com/3d.php?user=Notch&hrh=-20&aa=true`
18 | This example will only set the user to Notch, head rotation to -20 and AA (image smoothing) to true. You can add parameters by adding `&=` to the end of your URL.
19 |
20 | ### Parameters
21 | Supermamie's old parameters will still work.
22 |
23 | Parameters are now optional (exept for `user`), so you can now only add those you need.
24 |
25 | - `user` = Minecraft's username for the skin to be rendered. Required
26 | - `vr` = Vertical Rotation `-25 by default`
27 | - `hr` = Horizontal Rotation `35 by default`
28 | - `hrh` = Horizontal Rotation Head `0 by default`
29 | - `vrll` = Vertical Rotation Left Leg `0 by default`
30 | - `vrrl` = Vertical Rotation Right Leg `0 by default`
31 | - `vrla` = Vertical Rotation Left Arm `0 by default`
32 | - `vrra` = Vertical Rotation Right Arm `0 by default`
33 | - `displayHair` = Either or not to display hairs. Set to "false" to NOT display hairs. `true by default`
34 | - `headOnly` = Either or not to display the ONLY the head. Set to "true" to display ONLY the head (and the hair, based on displayHair). `false by default`
35 | - `format` = The format in which the image is to be rendered. PNG ("png") is used by default. Set to "svg" to use a vector version and "base64" for an encoded base64 string of the png image. `png by default`
36 | - `ratio` = The size of the "png" image. The default and minimum value is 2. `12 by default`
37 | - `aa` = Anti-aliasing (Not real AA, fake AA). When set to "true" the image will be smoother. `false by default`
38 | - `layers` = Apply extra skin layers. `true by default`
39 |
40 | ### Using it as class
41 | You can use the script for direct browser output (via the URL method as mentioned above), but also as a class for your scripts. Example:
42 |
43 | ```php
44 | include_once realpath(dirname(__FILE__) . '/3d.php');
45 |
46 | $player = new render3DPlayer('Notch', '-25', '-25', '10', '5', '-2', '-20', '2', 'true', 'false', 'png', '12', 'true', 'true'); //render3DPlayer(user, vr, hr, hrh, vrll, vrrl, vrla, vrra, displayHair, headOnly, format, ratio, aa, layers)
47 | $png = $player->get3DRender();
48 | echo "
====
PNG:
====
";
49 | echo $png; // TrueColor image
50 |
51 | $player = new render3DPlayer('Notch', '-25', '-25', '10', '5', '-2', '-20', '2', 'true', 'false', 'base64', '12', 'true', 'true'); //render3DPlayer(user, vr, hr, hrh, vrll, vrrl, vrla, vrra, displayHair, headOnly, format, ratio, aa, layers)
52 | $base64 = $player->get3DRender();
53 | echo "
========
Base 64:
========
";
54 | echo $base64; // Base64 string
55 |
56 | $player = new render3DPlayer('Notch', '-25', '-25', '10', '5', '-2', '-20', '2', 'true', 'false', 'svg', '12', 'true', 'true'); //render3DPlayer(user, vr, hr, hrh, vrll, vrrl, vrla, vrra, displayHair, headOnly, format, ratio, aa, layers)
57 | $svg = $player->get3DRender();
58 | echo "
====
SVG:
====
";
59 | echo $svg; // SVG String
60 |
61 | // As above (svg example) but with a locally provided file
62 | $player = new render3DPlayer('', '-25', '-25', '10', '5', '-2', '-20', '2', 'true', 'false', 'svg', '12', 'true', 'true', 'someskinfile.png');
63 | $svg = $player->get3DRender();
64 | echo "
====
SVG:
====
";
65 | echo $svg; // SVG String
66 |
67 | ```
68 |
69 | ### Changes Made
70 | - Fixed dark blue skins;
71 | - Fixed not working SVG images (Bug in cajogos fork);
72 | - Fixed non-transparent PNG images rendering incorrect (Fix is a bit experimental);
73 | - Fixed incorrect rendering texture parts;
74 | - Made the old parameters by supermamie work again;
75 | - Made 1.8 skins work;
76 | - Made 1.8 skins base layers render;
77 | - Added QUICK fix for 1.8 extra skin layers;
78 | - Added ability to output an encoded base64 string of the image;
79 | - Added optional AA (image smoothing) parameter;
80 | - Added UUID support. (Mojang does not want too many UUID requests so it might fail when you use it a lot);
81 | - Reformatted the entire code;
82 | - Made it possible to use the script as class;
83 | - Made all parameters optional;
84 | - Made Steve the fallback image.
85 |
--------------------------------------------------------------------------------
/3d.php:
--------------------------------------------------------------------------------
1 | array('old' => 'login', 'default' => false),
64 | 'vr' => array('old' => 'a', 'default' => '-25'),
65 | 'hr' => array('old' => 'w', 'default' => '35'),
66 | 'hrh' => array('old' => 'wt', 'default' => '0'),
67 | 'vrll' => array('old' => 'ajg', 'default' => '0'),
68 | 'vrrl' => array('old' => 'ajd', 'default' => '0'),
69 | 'vrla' => array('old' => 'abg', 'default' => '0'),
70 | 'vrra' => array('old' => 'abd', 'default' => '0'),
71 | 'displayHair' => array('old' => 'displayHairs', 'default' => 'true'),
72 | 'headOnly' => array('old' => 'headOnly', 'default' => 'false'),
73 | 'format' => array('old' => 'format', 'default' => 'png'),
74 | 'ratio' => array('old' => 'ratio', 'default' => '12'),
75 | 'aa' => array('old' => 'aa', 'default' => 'false'),
76 | 'layers' => array('old' => 'layers', 'default' => 'true')
77 | );
78 |
79 | if(array_key_exists($name, $parameters)) {
80 | if(isset($_GET[$name])) {
81 | return $_GET[$name];
82 | } else if (isset($_GET[$parameters[$name]['old']])) {
83 | return $_GET[$parameters[$name]['old']];
84 | }
85 | return $parameters[$name]['default'];
86 | }
87 |
88 | return false;
89 | }
90 |
91 | // Check if the player name value has been set, and that we are not running as an included/required file. else do nothing.
92 | if(( basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"]) ) && grabGetValue('user') !== false) {
93 | // There is a player name so they want an image output via url
94 | $player = new render3DPlayer( grabGetValue('user'),
95 | grabGetValue('vr'),
96 | grabGetValue('hr'),
97 | grabGetValue('hrh'),
98 | grabGetValue('vrll'),
99 | grabGetValue('vrrl'),
100 | grabGetValue('vrla'),
101 | grabGetValue('vrra'),
102 | grabGetValue('displayHair'),
103 | grabGetValue('headOnly'),
104 | grabGetValue('format'),
105 | grabGetValue('ratio'),
106 | grabGetValue('aa'),
107 | grabGetValue('layers')
108 | );
109 | $player->get3DRender('browser');
110 | }
111 |
112 | /* Render3DPlayer class
113 | *
114 | */
115 | class render3DPlayer {
116 | private $fallback_img = 'char.png'; // Use a not found skin whenever something goes wrong.
117 | private $localSkinFile = null;
118 | private $playerName = null;
119 | private $playerSkin = false;
120 | private $isNewSkinType = false;
121 |
122 | private $hd_ratio = 1;
123 |
124 | private $vR = null;
125 | private $hR = null;
126 | private $hrh = null;
127 | private $vrll = null;
128 | private $vrrl = null;
129 | private $vrla = null;
130 | private $vrra = null;
131 | private $head_only = null;
132 | private $display_hair = null;
133 | private $format = null;
134 | private $ratio = null;
135 | private $aa = null;
136 | private $layers = null;
137 |
138 | // Rotation variables in radians (3D Rendering)
139 | private $alpha = null; // Vertical rotation on the X axis.
140 | private $omega = null; // Horizontal rotation on the Y axis.
141 |
142 | private $members_angles = array(); // Head, Helmet, Torso, Arms, Legs
143 |
144 | private $visible_faces_format = null;
145 | private $visible_faces = null;
146 | private $all_faces = null;
147 |
148 | private $front_faces = null;
149 | private $back_faces = null;
150 |
151 | private $cube_points = null;
152 |
153 | private $polygons = null;
154 |
155 | private $times = null;
156 |
157 | public function __construct($user, $vr, $hr, $hrh, $vrll, $vrrl, $vrla, $vrra, $displayHair, $headOnly, $format, $ratio, $aa, $layers, $localFile = null) {
158 | $this->playerName = $user;
159 | $this->vR = $vr;
160 | $this->hR = $hr;
161 | $this->hrh = $hrh;
162 | $this->vrll = $vrll;
163 | $this->vrrl = $vrrl;
164 | $this->vrla = $vrla;
165 | $this->vrra = $vrra;
166 | $this->head_only = ($headOnly == 'true');
167 | $this->display_hair = ($displayHair != 'false');
168 | $this->format = $format;
169 | $this->ratio = $ratio;
170 | $this->aa = ($aa == 'true');
171 | $this->layers = ($layers == 'true');
172 | $this->localSkinFile = $localFile;
173 | }
174 |
175 | /* Function can be used for tracking script duration
176 | *
177 | */
178 | private function microtime_float() {
179 | list($usec, $sec) = explode(" ", microtime());
180 | return ((float) $usec + (float) $sec);
181 | }
182 |
183 | /* Function checs if given string is an UUID
184 | *
185 | * Return true or false
186 | */
187 | private function isUUID($candidate) {
188 | if (is_string($candidate)) {
189 | // Still needs a better UUID check system
190 | $trimmed = str_replace('-', '', $candidate);
191 | if (strlen($trimmed) === 32){
192 | return $trimmed;
193 | }
194 | }
195 | return false;
196 | }
197 |
198 | /* Function gets the player skin URL via the Mojang service by UUID
199 | *
200 | * Espects an UUID.
201 | * Returns player skin texure link, false on failure
202 | */
203 |
204 | private function getSkinURLViaUUIDViaMojang($UUID) {
205 | $mojangServiceContent = file_get_contents('https://sessionserver.mojang.com/session/minecraft/profile/' . $UUID);
206 | $contentArray = json_decode($mojangServiceContent, true);
207 |
208 | if(!is_array($contentArray)) {
209 | return false;
210 | }
211 |
212 | if(array_key_exists("properties", $contentArray)) {
213 | foreach($contentArray["properties"] as $element) {
214 | if(array_key_exists("name", $element) && $element["name"] == "textures") {
215 | $content = base64_decode($element["value"]);
216 | $skinArray = json_decode($content, true);
217 |
218 | if(!array_key_exists("textures", $skinArray)) {
219 | break;
220 | }
221 |
222 | if(!array_key_exists("SKIN", $skinArray["textures"])) {
223 | break;
224 | }
225 |
226 | return $skinArray["textures"]["SKIN"]["url"];
227 | }
228 | }
229 | }
230 |
231 | return false;
232 | }
233 |
234 | /* Create a skin URL from the given name or UUID
235 | *
236 | * Espects an UUID or a name
237 | * returns a player skin link
238 | */
239 |
240 | private function getSkinURL() {
241 | $isUUID = $this->isUUID($this->playerName);
242 | if($isUUID !== false) {
243 | $result = $this->getSkinURLViaUUIDViaMojang($isUUID);
244 | return $result;
245 | }
246 | else{
247 | $mojangProfileContent = file_get_contents('https://api.mojang.com/users/profiles/minecraft/' . $this->playerName . '?at=' . time());
248 | $profileContentArray = json_decode($mojangProfileContent, true);
249 | if(is_array($profileContentArray)) {
250 | if(!array_key_exists("id", $profileContentArray)) {
251 | return false;
252 | }
253 | }
254 | $result = $this->getSkinURLViaUUIDViaMojang($profileContentArray["id"]);
255 | return $result;
256 | }
257 | return false;
258 | }
259 |
260 | /* Function grabs the player skin from the Mojang server and checks it.
261 | *
262 | * Returns true on success, false on failure.
263 | */
264 | private function getPlayerSkin() {
265 |
266 | // If a local file has been provided, use this instead of downloading one
267 | if ($this->localSkinFile != null) {
268 | $this->playerSkin = @imageCreateFromPng($this->localSkinFile);
269 | } elseif (trim($this->playerName) == '') {
270 | $this->playerSkin = imageCreateFromPng($this->fallback_img);
271 | return false;
272 | } else {
273 | $skinURL = $this->getSkinURL();
274 | if($skinURL !== false) {
275 | $this->playerSkin = @imageCreateFromPng($skinURL);
276 | }
277 | // If failed to get skin URL via UUID: Did you tried it multiple times? Because Mojang does not accept too many requests!
278 | }
279 |
280 | if (!$this->playerSkin) {
281 | // Player skin does not exist
282 | $this->playerSkin = imageCreateFromPng($this->fallback_img);
283 | return false;
284 | }
285 |
286 | if (imagesy($this->playerSkin) % 32 != 0) {
287 | // Bad ratio created
288 | $this->playerSkin = imageCreateFromPng($this->fallback_img);
289 | return false;
290 | }
291 |
292 | return true;
293 | }
294 |
295 | /* Function renders the 3d image
296 | *
297 | */
298 | public function get3DRender($output = 'return') {
299 | global $minX, $maxX, $minY, $maxY;
300 |
301 | $this->times = array(array('Start', $this->microtime_float()));
302 | $this->getPlayerSkin(); // Downlaod and check the player skin
303 | $this->times[] = array('Download-Image', $this->microtime_float());
304 |
305 | $this->hd_ratio = imagesx($this->playerSkin) / 64; // Set HD ratio to 2 if the skin is 128x64. Check via width, not height because of new skin type.
306 |
307 | // check if new skin type. If both sides are equaly long: new skin type
308 | if(imagesx($this->playerSkin) == imagesy($this->playerSkin)) {
309 | $this->isNewSkinType = true;
310 | }
311 |
312 | $this->playerSkin = img::convertToTrueColor($this->playerSkin); // Convert the image to true color if not a true color image
313 | $this->times[] = array('Convert-to-true-color-if-needed', $this->microtime_float());
314 | $this->makeBackgroundTransparent(); // make background transparent (fix for weird rendering skins)
315 | $this->times[] = array('Made-Background-Transparent', $this->microtime_float());
316 |
317 | // Quick fix for 1.8:
318 | // Copy the extra layers ontop of the base layers
319 | if($this->layers) {
320 | $this->fixNewSkinTypeLayers();
321 | }
322 |
323 | $this->calculateAngles();
324 | $this->times[] = array('Angle-Calculations', $this->microtime_float());
325 | $this->facesDetermination();
326 | $this->times[] = array('Determination-of-faces', $this->microtime_float());
327 | $this->generatePolygons();
328 | $this->times[] = array('Polygon-generation', $this->microtime_float());
329 | $this->memberRotation();
330 | $this->times[] = array('Members-rotation', $this->microtime_float());
331 | $this->createProjectionPlan();
332 | $this->times[] = array('Projection-plan', $this->microtime_float());
333 | $result = $this->displayImage($output);
334 | $this->times[] = array('Display-image', $this->microtime_float());
335 |
336 | if($output == 'return') {
337 | return $result;
338 | }
339 |
340 | for ( $i = 1; $i < count( $this->times ); $i++ ) {
341 | header( 'generation-time-' . $i . '-' . $this->times[ $i ][ 0 ] . ': ' . ( $this->times[ $i ][ 1 ] - $this->times[ $i - 1 ][ 1 ] ) * 1000 . 'ms' );
342 | }
343 | header( 'generation-time-' . count( $this->times ) . '-TOTAL: ' . ( $this->times[ count( $this->times ) - 1 ][ 1 ] - $this->times[ 0 ][ 1 ] ) * 1000 . 'ms' );
344 |
345 | switch($this->format) {
346 | case 'svg':
347 | header( 'Content-Type: image/svg+xml' );
348 | echo '
349 | ' . $result . "\n";
351 |
352 | for ( $i = 1; $i < count( $this->times ); $i++ ) {
353 | echo '' . "\n";
354 | }
355 | echo '' . "\n";
356 |
357 | break;
358 | case 'base64':
359 | header('Content-Type: text/plain');
360 | echo $result;
361 | break;
362 | case 'png':
363 | default:
364 | header('Content-type: image/png');
365 | imagepng($result);
366 | imagedestroy($result);
367 | break;
368 | }
369 | }
370 |
371 | /* Function fixes issues with images that have a solid background
372 | *
373 | * Espects an tru color image.
374 | */
375 | private function makeBackgroundTransparent() {
376 | // check if the corner box is one solid color
377 | $tempValue = null;
378 | $needRemove = true;
379 |
380 | for ($iH = 0; $iH < 8; $iH++) {
381 | for ($iV = 0; $iV < 8; $iV++) {
382 | $pixelColor = imagecolorat($this->playerSkin, $iH, $iV);
383 |
384 | $indexColor = imagecolorsforindex($this->playerSkin, $pixelColor);
385 | if($indexColor['alpha'] > 120) {
386 | // the image contains transparancy, noting to do
387 | $needRemove = false;
388 | }
389 |
390 | if($tempValue === null) {
391 | $tempValue = $pixelColor;
392 | } else if ($tempValue != $pixelColor){
393 | // Cannot determine a background color, file is probably fine
394 | $needRemove = false;
395 | }
396 | }
397 | }
398 |
399 | $imgX = imagesx($this->playerSkin);
400 | $imgY = imagesy($this->playerSkin);
401 |
402 | $dst = img::createEmptyCanvas($imgX, $imgY);
403 |
404 | imagesavealpha($this->playerSkin, false);
405 |
406 | if($needRemove) {
407 | // the entire block is one solid color. Use this color to clear the background.
408 | $r = ($tempValue >> 16) & 0xFF;
409 | $g = ($tempValue >> 8) & 0xFF;
410 | $b = $tempValue & 0xFF;
411 |
412 |
413 | //imagealphablending($dst, true);
414 | $transparant = imagecolorallocate($this->playerSkin, $r, $g, $b);
415 | imagecolortransparent($this->playerSkin, $transparant);
416 |
417 | // create fill
418 | $color = imagecolorallocate($dst, $r, $g, $b);
419 | } else {
420 | // create fill
421 | $color = imagecolorallocate($dst, 0, 0, 0);
422 | }
423 |
424 | // fill the areas that should not be transparant
425 | $positionMultiply = $imgX / 64;
426 |
427 | // head
428 | imagefilledrectangle($dst, 8*$positionMultiply, 0*$positionMultiply, 23*$positionMultiply, 7*$positionMultiply, $color);
429 | imagefilledrectangle($dst, 0*$positionMultiply, 8*$positionMultiply, 31*$positionMultiply, 15*$positionMultiply, $color);
430 |
431 | // right leg, body, right arm
432 | imagefilledrectangle($dst, 4*$positionMultiply, 16*$positionMultiply, 11*$positionMultiply, 19*$positionMultiply, $color);
433 | imagefilledrectangle($dst, 20*$positionMultiply, 16*$positionMultiply, 35*$positionMultiply, 19*$positionMultiply, $color);
434 | imagefilledrectangle($dst, 44*$positionMultiply, 16*$positionMultiply, 51*$positionMultiply, 19*$positionMultiply, $color);
435 | imagefilledrectangle($dst, 0*$positionMultiply, 20*$positionMultiply, 54*$positionMultiply, 31*$positionMultiply, $color);
436 |
437 | // left leg, left arm
438 | imagefilledrectangle($dst, 20*$positionMultiply, 48*$positionMultiply, 27*$positionMultiply, 51*$positionMultiply, $color);
439 | imagefilledrectangle($dst, 36*$positionMultiply, 48*$positionMultiply, 43*$positionMultiply, 51*$positionMultiply, $color);
440 | imagefilledrectangle($dst, 16*$positionMultiply, 52*$positionMultiply, 47*$positionMultiply, 63*$positionMultiply, $color);
441 |
442 | imagecopy($dst, $this->playerSkin, 0, 0, 0, 0, $imgX, $imgY);
443 |
444 | $this->playerSkin = $dst;
445 | return;
446 | }
447 |
448 | /* Function converts a 1.8 skin (which is not supported by
449 | * the script) to the old skin format.
450 | *
451 | * Espects an image.
452 | * Returns a croped image.
453 | */
454 | private function cropToOldSkinFormat() {
455 | if(imagesx($this->playerSkin) !== imagesy($this->playerSkin)) {
456 | return $this->playerSkin;
457 | }
458 |
459 | $newWidth = imagesx($this->playerSkin);
460 | $newHeight = $newWidth / 2;
461 |
462 | $newImgPng = img::createEmptyCanvas($newWidth, $newHeight);
463 |
464 | imagecopy($newImgPng, $this->playerSkin, 0, 0, 0, 0, $newWidth, $newHeight);
465 |
466 | $this->playerSkin = $newImgPng;
467 | }
468 |
469 | /* Function copys the extra layers of a 1.8 skin
470 | * onto the base layers so that it will still show. QUICK FIX, NEEDS BETTER FIX
471 | *
472 | * Espects an image.
473 | * Returns a croped image.
474 | */
475 | private function fixNewSkinTypeLayers() {
476 | if(!$this->isNewSkinType) {
477 | return;
478 | }
479 |
480 | imagecopy($this->playerSkin, $this->playerSkin, 0, 16, 0, 32, 56, 16); // RL2, BODY2, RA2
481 | imagecopy($this->playerSkin, $this->playerSkin, 16, 48, 0, 48, 16, 16); // LL2
482 | imagecopy($this->playerSkin, $this->playerSkin, 32, 48, 48, 48, 16, 16); // LA2
483 | }
484 |
485 | /* Function Calculates the angels
486 | *
487 | */
488 | private function calculateAngles() {
489 | global $cos_alpha, $sin_alpha, $cos_omega, $sin_omega;
490 | global $minX, $maxX, $minY, $maxY;
491 |
492 | // Rotation variables in radians (3D Rendering)
493 | $this->alpha = deg2rad($this->vR); // Vertical rotation on the X axis.
494 | $this->omega = deg2rad($this->hR); // Horizontal rotation on the Y axis.
495 |
496 | // Cosine and Sine values
497 | $cos_alpha = cos($this->alpha);
498 | $sin_alpha = sin($this->alpha);
499 | $cos_omega = cos($this->omega);
500 | $sin_omega = sin($this->omega);
501 |
502 | $this->members_angles['torso'] = array(
503 | 'cos_alpha' => cos(0),
504 | 'sin_alpha' => sin(0),
505 | 'cos_omega' => cos(0),
506 | 'sin_omega' => sin(0)
507 | );
508 |
509 | $alpha_head = 0;
510 | $omega_head = deg2rad($this->hrh);
511 | $this->members_angles['head'] = $this->members_angles['helmet'] = array( // Head and helmet get the same calculations
512 | 'cos_alpha' => cos($alpha_head),
513 | 'sin_alpha' => sin($alpha_head),
514 | 'cos_omega' => cos($omega_head),
515 | 'sin_omega' => sin($omega_head)
516 | );
517 |
518 | $alpha_right_arm = deg2rad($this->vrra);
519 | $omega_right_arm = 0;
520 | $this->members_angles['rightArm'] = array(
521 | 'cos_alpha' => cos($alpha_right_arm),
522 | 'sin_alpha' => sin($alpha_right_arm),
523 | 'cos_omega' => cos($omega_right_arm),
524 | 'sin_omega' => sin($omega_right_arm)
525 | );
526 |
527 | $alpha_left_arm = deg2rad($this->vrla);
528 | $omega_left_arm = 0;
529 | $this->members_angles['leftArm'] = array(
530 | 'cos_alpha' => cos($alpha_left_arm),
531 | 'sin_alpha' => sin($alpha_left_arm),
532 | 'cos_omega' => cos($omega_left_arm),
533 | 'sin_omega' => sin($omega_left_arm)
534 | );
535 |
536 | $alpha_right_leg = deg2rad($this->vrrl);
537 | $omega_right_leg = 0;
538 | $this->members_angles['rightLeg'] = array(
539 | 'cos_alpha' => cos($alpha_right_leg),
540 | 'sin_alpha' => sin($alpha_right_leg),
541 | 'cos_omega' => cos($omega_right_leg),
542 | 'sin_omega' => sin($omega_right_leg)
543 | );
544 |
545 | $alpha_left_leg = deg2rad($this->vrll);
546 | $omega_left_leg = 0;
547 | $this->members_angles['leftLeg'] = array(
548 | 'cos_alpha' => cos($alpha_left_leg),
549 | 'sin_alpha' => sin($alpha_left_leg),
550 | 'cos_omega' => cos($omega_left_leg),
551 | 'sin_omega' => sin($omega_left_leg)
552 | );
553 | $minX = 0;
554 | $maxX = 0;
555 | $minY = 0;
556 | $maxY = 0;
557 | }
558 |
559 | /* Function determinates faces
560 | *
561 | */
562 | private function facesDetermination() {
563 | $this->visible_faces_format = array(
564 | 'front' => array(),
565 | 'back' => array ()
566 | );
567 |
568 | $this->visible_faces = array(
569 | 'head' => $this->visible_faces_format,
570 | 'torso' => $this->visible_faces_format,
571 | 'rightArm' => $this->visible_faces_format,
572 | 'leftArm' => $this->visible_faces_format,
573 | 'rightLeg' => $this->visible_faces_format,
574 | 'leftLeg' => $this->visible_faces_format
575 | );
576 |
577 | $this->all_faces = array(
578 | 'back',
579 | 'right',
580 | 'top',
581 | 'front',
582 | 'left',
583 | 'bottom'
584 | );
585 |
586 | // Loop each preProject and Project then calculate the visible faces for each - also display
587 | foreach ($this->visible_faces as $k => &$v) {
588 | unset($cube_max_depth_faces, $this->cube_points);
589 |
590 | $this->setCubePoints();
591 |
592 | foreach ($this->cube_points as $cube_point) {
593 | $cube_point[0]->preProject(0, 0, 0,
594 | $this->members_angles[$k]['cos_alpha'],
595 | $this->members_angles[$k]['sin_alpha'],
596 | $this->members_angles[$k]['cos_omega'],
597 | $this->members_angles[$k]['sin_omega']);
598 | $cube_point[0]->project();
599 |
600 | if (!isset($cube_max_depth_faces)) {
601 | $cube_max_depth_faces = $cube_point;
602 | } else if ($cube_max_depth_faces[0]->getDepth() > $cube_point[0]->getDepth()) {
603 | $cube_max_depth_faces = $cube_point;
604 | }
605 | }
606 |
607 | $v['back'] = $cube_max_depth_faces[1];
608 | $v['front'] = array_diff($this->all_faces, $v['back']);
609 | }
610 |
611 | $this->setCubePoints();
612 |
613 | unset($cube_max_depth_faces);
614 | foreach ($this->cube_points as $cube_point) {
615 | $cube_point[0]->project();
616 |
617 | if (!isset($cube_max_depth_faces)) {
618 | $cube_max_depth_faces = $cube_point;
619 | } else if ($cube_max_depth_faces[0]->getDepth() > $cube_point[ 0 ]->getDepth()) {
620 | $cube_max_depth_faces = $cube_point;
621 | }
622 |
623 | $this->back_faces = $cube_max_depth_faces[ 1 ];
624 | $this->front_faces = array_diff($this->all_faces, $this->back_faces );
625 | }
626 | }
627 |
628 | /* Function sets all cube points
629 | *
630 | */
631 | private function setCubePoints() {
632 | $this->cube_points = array();
633 | $this->cube_points[] = array(
634 | new Point(array(
635 | 'x' => 0,
636 | 'y' => 0,
637 | 'z' => 0
638 | )), array(
639 | 'back',
640 | 'right',
641 | 'top'
642 | )); // 0
643 |
644 | $this->cube_points[] = array(
645 | new Point(array(
646 | 'x' => 0,
647 | 'y' => 0,
648 | 'z' => 1
649 | )), array(
650 | 'front',
651 | 'right',
652 | 'top'
653 | )); // 1
654 |
655 | $this->cube_points[] = array(
656 | new Point(array(
657 | 'x' => 0,
658 | 'y' => 1,
659 | 'z' => 0
660 | )), array(
661 | 'back',
662 | 'right',
663 | 'bottom'
664 | )); // 2
665 |
666 | $this->cube_points[] = array(
667 | new Point(array(
668 | 'x' => 0,
669 | 'y' => 1,
670 | 'z' => 1
671 | )), array(
672 | 'front',
673 | 'right',
674 | 'bottom'
675 | )); // 3
676 |
677 | $this->cube_points[] = array(
678 | new Point(array(
679 | 'x' => 1,
680 | 'y' => 0,
681 | 'z' => 0
682 | )), array(
683 | 'back',
684 | 'left',
685 | 'top'
686 | )); // 4
687 |
688 | $this->cube_points[] = array(
689 | new Point(array(
690 | 'x' => 1,
691 | 'y' => 0,
692 | 'z' => 1
693 | )), array(
694 | 'front',
695 | 'left',
696 | 'top'
697 | )); // 5
698 |
699 | $this->cube_points[] = array(
700 | new Point(array(
701 | 'x' => 1,
702 | 'y' => 1,
703 | 'z' => 0
704 | )), array(
705 | 'back',
706 | 'left',
707 | 'bottom'
708 | )); // 6
709 |
710 | $this->cube_points[] = array(
711 | new Point(array(
712 | 'x' => 1,
713 | 'y' => 1,
714 | 'z' => 1
715 | )), array(
716 | 'front',
717 | 'left',
718 | 'bottom'
719 | )); // 7
720 | }
721 |
722 | /* Function generates polygons
723 | *
724 | */
725 | private function generatePolygons() {
726 | $depths_of_face = array();
727 | $this->polygons = array();
728 | $cube_faces_array = array( 'front' => array(),
729 | 'back' => array(),
730 | 'top' => array(),
731 | 'bottom' => array(),
732 | 'right' => array(),
733 | 'left' => array ()
734 | );
735 |
736 | $this->polygons = array('helmet' => $cube_faces_array,
737 | 'head' => $cube_faces_array,
738 | 'torso' => $cube_faces_array,
739 | 'rightArm' => $cube_faces_array,
740 | 'leftArm' => $cube_faces_array,
741 | 'rightLeg' => $cube_faces_array,
742 | 'leftLeg' => $cube_faces_array
743 | );
744 |
745 | $hd_ratio = $this->hd_ratio;
746 | $img_png = $this->playerSkin;
747 |
748 | // HEAD
749 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
750 | for ( $j = 0; $j < 9 * $hd_ratio; $j++ ) {
751 | if ( !isset( $volume_points[ $i ][ $j ][ -2 * $hd_ratio ] ) ) {
752 | $volume_points[ $i ][ $j ][ -2 * $hd_ratio ] = new Point( array(
753 | 'x' => $i,
754 | 'y' => $j,
755 | 'z' => -2 * $hd_ratio
756 | ) );
757 | }
758 | if ( !isset( $volume_points[ $i ][ $j ][ 6 * $hd_ratio ] ) ) {
759 | $volume_points[ $i ][ $j ][ 6 * $hd_ratio ] = new Point( array(
760 | 'x' => $i,
761 | 'y' => $j,
762 | 'z' => 6 * $hd_ratio
763 | ) );
764 | }
765 | }
766 | }
767 | for ( $j = 0; $j < 9 * $hd_ratio; $j++ ) {
768 | for ( $k = -2 * $hd_ratio; $k < 7 * $hd_ratio; $k++ ) {
769 | if ( !isset( $volume_points[ 0 ][ $j ][ $k ] ) ) {
770 | $volume_points[ 0 ][ $j ][ $k ] = new Point( array(
771 | 'x' => 0,
772 | 'y' => $j,
773 | 'z' => $k
774 | ) );
775 | }
776 | if ( !isset( $volume_points[ 8 * $hd_ratio ][ $j ][ $k ] ) ) {
777 | $volume_points[ 8 * $hd_ratio ][ $j ][ $k ] = new Point( array(
778 | 'x' => 8 * $hd_ratio,
779 | 'y' => $j,
780 | 'z' => $k
781 | ) );
782 | }
783 | }
784 | }
785 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
786 | for ( $k = -2 * $hd_ratio; $k < 7 * $hd_ratio; $k++ ) {
787 | if ( !isset( $volume_points[ $i ][ 0 ][ $k ] ) ) {
788 | $volume_points[ $i ][ 0 ][ $k ] = new Point( array(
789 | 'x' => $i,
790 | 'y' => 0,
791 | 'z' => $k
792 | ) );
793 | }
794 | if ( !isset( $volume_points[ $i ][ 8 * $hd_ratio ][ $k ] ) ) {
795 | $volume_points[ $i ][ 8 * $hd_ratio ][ $k ] = new Point( array(
796 | 'x' => $i,
797 | 'y' => 8 * $hd_ratio,
798 | 'z' => $k
799 | ) );
800 | }
801 | }
802 | }
803 | for ( $i = 0; $i < 8 * $hd_ratio; $i++ ) {
804 | for ( $j = 0; $j < 8 * $hd_ratio; $j++ ) {
805 | $this->polygons[ 'head' ][ 'back' ][] = new Polygon( array(
806 | $volume_points[ $i ][ $j ][ -2 * $hd_ratio ],
807 | $volume_points[ $i + 1 ][ $j ][ -2 * $hd_ratio ],
808 | $volume_points[ $i + 1 ][ $j + 1 ][ -2 * $hd_ratio ],
809 | $volume_points[ $i ][ $j + 1 ][ -2 * $hd_ratio ]
810 | ), imagecolorat( $img_png, ( 32 * $hd_ratio - 1 ) - $i, 8 * $hd_ratio + $j ) );
811 | $this->polygons[ 'head' ][ 'front' ][] = new Polygon( array(
812 | $volume_points[ $i ][ $j ][ 6 * $hd_ratio ],
813 | $volume_points[ $i + 1 ][ $j ][ 6 * $hd_ratio ],
814 | $volume_points[ $i + 1 ][ $j + 1 ][ 6 * $hd_ratio ],
815 | $volume_points[ $i ][ $j + 1 ][ 6 * $hd_ratio ]
816 | ), imagecolorat( $img_png, 8 * $hd_ratio + $i, 8 * $hd_ratio + $j ) );
817 | }
818 | }
819 | for ( $j = 0; $j < 8 * $hd_ratio; $j++ ) {
820 | for ( $k = -2 * $hd_ratio; $k < 6 * $hd_ratio; $k++ ) {
821 | $this->polygons[ 'head' ][ 'right' ][] = new Polygon( array(
822 | $volume_points[ 0 ][ $j ][ $k ],
823 | $volume_points[ 0 ][ $j ][ $k + 1 ],
824 | $volume_points[ 0 ][ $j + 1 ][ $k + 1 ],
825 | $volume_points[ 0 ][ $j + 1 ][ $k ]
826 | ), imagecolorat( $img_png, $k + 2 * $hd_ratio, 8 * $hd_ratio + $j ) );
827 | $this->polygons[ 'head' ][ 'left' ][] = new Polygon( array(
828 | $volume_points[ 8 * $hd_ratio ][ $j ][ $k ],
829 | $volume_points[ 8 * $hd_ratio ][ $j ][ $k + 1 ],
830 | $volume_points[ 8 * $hd_ratio ][ $j + 1 ][ $k + 1 ],
831 | $volume_points[ 8 * $hd_ratio ][ $j + 1 ][ $k ]
832 | ), imagecolorat( $img_png, ( 24 * $hd_ratio - 1 ) - $k - 2 * $hd_ratio, 8 * $hd_ratio + $j ) );
833 | }
834 | }
835 | for ( $i = 0; $i < 8 * $hd_ratio; $i++ ) {
836 | for ( $k = -2 * $hd_ratio; $k < 6 * $hd_ratio; $k++ ) {
837 | $this->polygons[ 'head' ][ 'top' ][] = new Polygon( array(
838 | $volume_points[ $i ][ 0 ][ $k ],
839 | $volume_points[ $i + 1 ][ 0 ][ $k ],
840 | $volume_points[ $i + 1 ][ 0 ][ $k + 1 ],
841 | $volume_points[ $i ][ 0 ][ $k + 1 ]
842 | ), imagecolorat( $img_png, 8 * $hd_ratio + $i, $k + 2 * $hd_ratio ) );
843 | $this->polygons[ 'head' ][ 'bottom' ][] = new Polygon( array(
844 | $volume_points[ $i ][ 8 * $hd_ratio ][ $k ],
845 | $volume_points[ $i + 1 ][ 8 * $hd_ratio ][ $k ],
846 | $volume_points[ $i + 1 ][ 8 * $hd_ratio ][ $k + 1 ],
847 | $volume_points[ $i ][ 8 * $hd_ratio ][ $k + 1 ]
848 | ), imagecolorat( $img_png, 16 * $hd_ratio + $i, 2 * $hd_ratio + $k ) );
849 | }
850 | }
851 | if ($this->display_hair) {
852 | // HELMET/HAIR
853 | $volume_points = array();
854 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
855 | for ( $j = 0; $j < 9 * $hd_ratio; $j++ ) {
856 | if ( !isset( $volume_points[ $i ][ $j ][ -2 * $hd_ratio ] ) ) {
857 | $volume_points[ $i ][ $j ][ -2 * $hd_ratio ] = new Point( array(
858 | 'x' => $i * 9 / 8 - 0.5 * $hd_ratio,
859 | 'y' => $j * 9 / 8 - 0.5 * $hd_ratio,
860 | 'z' => -2.5 * $hd_ratio
861 | ) );
862 | }
863 | if ( !isset( $volume_points[ $i ][ $j ][ 6 * $hd_ratio ] ) ) {
864 | $volume_points[ $i ][ $j ][ 6 * $hd_ratio ] = new Point( array(
865 | 'x' => $i * 9 / 8 - 0.5 * $hd_ratio,
866 | 'y' => $j * 9 / 8 - 0.5 * $hd_ratio,
867 | 'z' => 6.5 * $hd_ratio
868 | ) );
869 | }
870 | }
871 | }
872 | for ( $j = 0; $j < 9 * $hd_ratio; $j++ ) {
873 | for ( $k = -2 * $hd_ratio; $k < 7 * $hd_ratio; $k++ ) {
874 | if ( !isset( $volume_points[ 0 ][ $j ][ $k ] ) ) {
875 | $volume_points[ 0 ][ $j ][ $k ] = new Point( array(
876 | 'x' => -0.5 * $hd_ratio,
877 | 'y' => $j * 9 / 8 - 0.5 * $hd_ratio,
878 | 'z' => $k * 9 / 8 - 0.5 * $hd_ratio
879 | ) );
880 | }
881 | if ( !isset( $volume_points[ 8 * $hd_ratio ][ $j ][ $k ] ) ) {
882 | $volume_points[ 8 * $hd_ratio ][ $j ][ $k ] = new Point( array(
883 | 'x' => 8.5 * $hd_ratio,
884 | 'y' => $j * 9 / 8 - 0.5 * $hd_ratio,
885 | 'z' => $k * 9 / 8 - 0.5 * $hd_ratio
886 | ) );
887 | }
888 | }
889 | }
890 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
891 | for ( $k = -2 * $hd_ratio; $k < 7 * $hd_ratio; $k++ ) {
892 | if ( !isset( $volume_points[ $i ][ 0 ][ $k ] ) ) {
893 | $volume_points[ $i ][ 0 ][ $k ] = new Point( array(
894 | 'x' => $i * 9 / 8 - 0.5 * $hd_ratio,
895 | 'y' => -0.5 * $hd_ratio,
896 | 'z' => $k * 9 / 8 - 0.5 * $hd_ratio
897 | ) );
898 | }
899 | if ( !isset( $volume_points[ $i ][ 8 * $hd_ratio ][ $k ] ) ) {
900 | $volume_points[ $i ][ 8 * $hd_ratio ][ $k ] = new Point( array(
901 | 'x' => $i * 9 / 8 - 0.5 * $hd_ratio,
902 | 'y' => 8.5 * $hd_ratio,
903 | 'z' => $k * 9 / 8 - 0.5 * $hd_ratio
904 | ) );
905 | }
906 | }
907 | }
908 | for ( $i = 0; $i < 8 * $hd_ratio; $i++ ) {
909 | for ( $j = 0; $j < 8 * $hd_ratio; $j++ ) {
910 | $this->polygons[ 'helmet' ][ 'back' ][] = new Polygon( array(
911 | $volume_points[ $i ][ $j ][ -2 * $hd_ratio ],
912 | $volume_points[ $i + 1 ][ $j ][ -2 * $hd_ratio ],
913 | $volume_points[ $i + 1 ][ $j + 1 ][ -2 * $hd_ratio ],
914 | $volume_points[ $i ][ $j + 1 ][ -2 * $hd_ratio ]
915 | ), imagecolorat( $img_png, 32 * $hd_ratio + ( 32 * $hd_ratio - 1 ) - $i, 8 * $hd_ratio + $j ) );
916 | $this->polygons[ 'helmet' ][ 'front' ][] = new Polygon( array(
917 | $volume_points[ $i ][ $j ][ 6 * $hd_ratio ],
918 | $volume_points[ $i + 1 ][ $j ][ 6 * $hd_ratio ],
919 | $volume_points[ $i + 1 ][ $j + 1 ][ 6 * $hd_ratio ],
920 | $volume_points[ $i ][ $j + 1 ][ 6 * $hd_ratio ]
921 | ), imagecolorat( $img_png, 32 * $hd_ratio + 8 * $hd_ratio + $i, 8 * $hd_ratio + $j ) );
922 | }
923 | }
924 | for ( $j = 0; $j < 8 * $hd_ratio; $j++ ) {
925 | for ( $k = -2 * $hd_ratio; $k < 6 * $hd_ratio; $k++ ) {
926 | $this->polygons[ 'helmet' ][ 'right' ][] = new Polygon( array(
927 | $volume_points[ 0 ][ $j ][ $k ],
928 | $volume_points[ 0 ][ $j ][ $k + 1 ],
929 | $volume_points[ 0 ][ $j + 1 ][ $k + 1 ],
930 | $volume_points[ 0 ][ $j + 1 ][ $k ]
931 | ), imagecolorat( $img_png, 32 * $hd_ratio + $k + 2 * $hd_ratio, 8 * $hd_ratio + $j ) );
932 | $this->polygons[ 'helmet' ][ 'left' ][] = new Polygon( array(
933 | $volume_points[ 8 * $hd_ratio ][ $j ][ $k ],
934 | $volume_points[ 8 * $hd_ratio ][ $j ][ $k + 1 ],
935 | $volume_points[ 8 * $hd_ratio ][ $j + 1 ][ $k + 1 ],
936 | $volume_points[ 8 * $hd_ratio ][ $j + 1 ][ $k ]
937 | ), imagecolorat( $img_png, 32 * $hd_ratio + ( 24 * $hd_ratio - 1 ) - $k - 2 * $hd_ratio, 8 * $hd_ratio + $j ) );
938 | }
939 | }
940 | for ( $i = 0; $i < 8 * $hd_ratio; $i++ ) {
941 | for ( $k = -2 * $hd_ratio; $k < 6 * $hd_ratio; $k++ ) {
942 | $this->polygons[ 'helmet' ][ 'top' ][] = new Polygon( array(
943 | $volume_points[ $i ][ 0 ][ $k ],
944 | $volume_points[ $i + 1 ][ 0 ][ $k ],
945 | $volume_points[ $i + 1 ][ 0 ][ $k + 1 ],
946 | $volume_points[ $i ][ 0 ][ $k + 1 ]
947 | ), imagecolorat( $img_png, 32 * $hd_ratio + 8 * $hd_ratio + $i, $k + 2 * $hd_ratio ) );
948 | $this->polygons[ 'helmet' ][ 'bottom' ][] = new Polygon( array(
949 | $volume_points[ $i ][ 8 * $hd_ratio ][ $k ],
950 | $volume_points[ $i + 1 ][ 8 * $hd_ratio ][ $k ],
951 | $volume_points[ $i + 1 ][ 8 * $hd_ratio ][ $k + 1 ],
952 | $volume_points[ $i ][ 8 * $hd_ratio ][ $k + 1 ]
953 | ), imagecolorat( $img_png, 32 * $hd_ratio + 16 * $hd_ratio + $i, 2 * $hd_ratio + $k ) );
954 | }
955 | }
956 | }
957 | if ( !$this->head_only ) {
958 | // TORSO
959 | $volume_points = array();
960 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
961 | for ( $j = 0; $j < 13 * $hd_ratio; $j++ ) {
962 | if ( !isset( $volume_points[ $i ][ $j ][ 0 ] ) ) {
963 | $volume_points[ $i ][ $j ][ 0 ] = new Point( array(
964 | 'x' => $i,
965 | 'y' => $j + 8 * $hd_ratio,
966 | 'z' => 0
967 | ) );
968 | }
969 | if ( !isset( $volume_points[ $i ][ $j ][ 4 * $hd_ratio ] ) ) {
970 | $volume_points[ $i ][ $j ][ 4 * $hd_ratio ] = new Point( array(
971 | 'x' => $i,
972 | 'y' => $j + 8 * $hd_ratio,
973 | 'z' => 4 * $hd_ratio
974 | ) );
975 | }
976 | }
977 | }
978 | for ( $j = 0; $j < 13 * $hd_ratio; $j++ ) {
979 | for ( $k = 0; $k < 5 * $hd_ratio; $k++ ) {
980 | if ( !isset( $volume_points[ 0 ][ $j ][ $k ] ) ) {
981 | $volume_points[ 0 ][ $j ][ $k ] = new Point( array(
982 | 'x' => 0,
983 | 'y' => $j + 8 * $hd_ratio,
984 | 'z' => $k
985 | ) );
986 | }
987 | if ( !isset( $volume_points[ 8 * $hd_ratio ][ $j ][ $k ] ) ) {
988 | $volume_points[ 8 * $hd_ratio ][ $j ][ $k ] = new Point( array(
989 | 'x' => 8 * $hd_ratio,
990 | 'y' => $j + 8 * $hd_ratio,
991 | 'z' => $k
992 | ) );
993 | }
994 | }
995 | }
996 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
997 | for ( $k = 0; $k < 5 * $hd_ratio; $k++ ) {
998 | if ( !isset( $volume_points[ $i ][ 0 ][ $k ] ) ) {
999 | $volume_points[ $i ][ 0 ][ $k ] = new Point( array(
1000 | 'x' => $i,
1001 | 'y' => 0 + 8 * $hd_ratio,
1002 | 'z' => $k
1003 | ) );
1004 | }
1005 | if ( !isset( $volume_points[ $i ][ 12 * $hd_ratio ][ $k ] ) ) {
1006 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k ] = new Point( array(
1007 | 'x' => $i,
1008 | 'y' => 12 * $hd_ratio + 8 * $hd_ratio,
1009 | 'z' => $k
1010 | ) );
1011 | }
1012 | }
1013 | }
1014 | for ( $i = 0; $i < 8 * $hd_ratio; $i++ ) {
1015 | for ( $j = 0; $j < 12 * $hd_ratio; $j++ ) {
1016 | $this->polygons[ 'torso' ][ 'back' ][] = new Polygon( array(
1017 | $volume_points[ $i ][ $j ][ 0 ],
1018 | $volume_points[ $i + 1 ][ $j ][ 0 ],
1019 | $volume_points[ $i + 1 ][ $j + 1 ][ 0 ],
1020 | $volume_points[ $i ][ $j + 1 ][ 0 ]
1021 | ), imagecolorat( $img_png, ( 40 * $hd_ratio - 1 ) - $i, 20 * $hd_ratio + $j ) );
1022 | $this->polygons[ 'torso' ][ 'front' ][] = new Polygon( array(
1023 | $volume_points[ $i ][ $j ][ 4 * $hd_ratio ],
1024 | $volume_points[ $i + 1 ][ $j ][ 4 * $hd_ratio ],
1025 | $volume_points[ $i + 1 ][ $j + 1 ][ 4 * $hd_ratio ],
1026 | $volume_points[ $i ][ $j + 1 ][ 4 * $hd_ratio ]
1027 | ), imagecolorat( $img_png, 20 * $hd_ratio + $i, 20 * $hd_ratio + $j ) );
1028 | }
1029 | }
1030 | for ( $j = 0; $j < 12 * $hd_ratio; $j++ ) {
1031 | for ( $k = 0; $k < 4 * $hd_ratio; $k++ ) {
1032 | $this->polygons[ 'torso' ][ 'right' ][] = new Polygon( array(
1033 | $volume_points[ 0 ][ $j ][ $k ],
1034 | $volume_points[ 0 ][ $j ][ $k + 1 ],
1035 | $volume_points[ 0 ][ $j + 1 ][ $k + 1 ],
1036 | $volume_points[ 0 ][ $j + 1 ][ $k ]
1037 | ), imagecolorat( $img_png, 16 * $hd_ratio + $k, 20 * $hd_ratio + $j ) );
1038 | $this->polygons[ 'torso' ][ 'left' ][] = new Polygon( array(
1039 | $volume_points[ 8 * $hd_ratio ][ $j ][ $k ],
1040 | $volume_points[ 8 * $hd_ratio ][ $j ][ $k + 1 ],
1041 | $volume_points[ 8 * $hd_ratio ][ $j + 1 ][ $k + 1 ],
1042 | $volume_points[ 8 * $hd_ratio ][ $j + 1 ][ $k ]
1043 | ), imagecolorat( $img_png, ( 32 * $hd_ratio - 1 ) - $k, 20 * $hd_ratio + $j ) );
1044 | }
1045 | }
1046 | for ( $i = 0; $i < 8 * $hd_ratio; $i++ ) {
1047 | for ( $k = 0; $k < 4 * $hd_ratio; $k++ ) {
1048 | $this->polygons[ 'torso' ][ 'top' ][] = new Polygon( array(
1049 | $volume_points[ $i ][ 0 ][ $k ],
1050 | $volume_points[ $i + 1 ][ 0 ][ $k ],
1051 | $volume_points[ $i + 1 ][ 0 ][ $k + 1 ],
1052 | $volume_points[ $i ][ 0 ][ $k + 1 ]
1053 | ), imagecolorat( $img_png, 20 * $hd_ratio + $i, 16 * $hd_ratio + $k ) );
1054 | $this->polygons[ 'torso' ][ 'bottom' ][] = new Polygon( array(
1055 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k ],
1056 | $volume_points[ $i + 1 ][ 12 * $hd_ratio ][ $k ],
1057 | $volume_points[ $i + 1 ][ 12 * $hd_ratio ][ $k + 1 ],
1058 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k + 1 ]
1059 | ), imagecolorat( $img_png, 28 * $hd_ratio + $i, ( 20 * $hd_ratio - 1 ) - $k ) );
1060 | }
1061 | }
1062 | // RIGHT ARM
1063 | $volume_points = array();
1064 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
1065 | for ( $j = 0; $j < 13 * $hd_ratio; $j++ ) {
1066 | if ( !isset( $volume_points[ $i ][ $j ][ 0 ] ) ) {
1067 | $volume_points[ $i ][ $j ][ 0 ] = new Point( array(
1068 | 'x' => $i - 4 * $hd_ratio,
1069 | 'y' => $j + 8 * $hd_ratio,
1070 | 'z' => 0
1071 | ) );
1072 | }
1073 | if ( !isset( $volume_points[ $i ][ $j ][ 4 * $hd_ratio ] ) ) {
1074 | $volume_points[ $i ][ $j ][ 4 * $hd_ratio ] = new Point( array(
1075 | 'x' => $i - 4 * $hd_ratio,
1076 | 'y' => $j + 8 * $hd_ratio,
1077 | 'z' => 4 * $hd_ratio
1078 | ) );
1079 | }
1080 | }
1081 | }
1082 | for ( $j = 0; $j < 13 * $hd_ratio; $j++ ) {
1083 | for ( $k = 0; $k < 5 * $hd_ratio; $k++ ) {
1084 | if ( !isset( $volume_points[ 0 ][ $j ][ $k ] ) ) {
1085 | $volume_points[ 0 ][ $j ][ $k ] = new Point( array(
1086 | 'x' => 0 - 4 * $hd_ratio,
1087 | 'y' => $j + 8 * $hd_ratio,
1088 | 'z' => $k
1089 | ) );
1090 | }
1091 | if ( !isset( $volume_points[ 8 * $hd_ratio ][ $j ][ $k ] ) ) {
1092 | $volume_points[ 4 * $hd_ratio ][ $j ][ $k ] = new Point( array(
1093 | 'x' => 4 * $hd_ratio - 4 * $hd_ratio,
1094 | 'y' => $j + 8 * $hd_ratio,
1095 | 'z' => $k
1096 | ) );
1097 | }
1098 | }
1099 | }
1100 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
1101 | for ( $k = 0; $k < 5 * $hd_ratio; $k++ ) {
1102 | if ( !isset( $volume_points[ $i ][ 0 ][ $k ] ) ) {
1103 | $volume_points[ $i ][ 0 ][ $k ] = new Point( array(
1104 | 'x' => $i - 4 * $hd_ratio,
1105 | 'y' => 0 + 8 * $hd_ratio,
1106 | 'z' => $k
1107 | ) );
1108 | }
1109 | if ( !isset( $volume_points[ $i ][ 12 * $hd_ratio ][ $k ] ) ) {
1110 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k ] = new Point( array(
1111 | 'x' => $i - 4 * $hd_ratio,
1112 | 'y' => 12 * $hd_ratio + 8 * $hd_ratio,
1113 | 'z' => $k
1114 | ) );
1115 | }
1116 | }
1117 | }
1118 | for ( $i = 0; $i < 4 * $hd_ratio; $i++ ) {
1119 | for ( $j = 0; $j < 12 * $hd_ratio; $j++ ) {
1120 | $this->polygons[ 'rightArm' ][ 'back' ][] = new Polygon( array(
1121 | $volume_points[ $i ][ $j ][ 0 ],
1122 | $volume_points[ $i + 1 ][ $j ][ 0 ],
1123 | $volume_points[ $i + 1 ][ $j + 1 ][ 0 ],
1124 | $volume_points[ $i ][ $j + 1 ][ 0 ]
1125 | ), imagecolorat( $img_png, ( 56 * $hd_ratio - 1 ) - $i, 20 * $hd_ratio + $j ) );
1126 | $this->polygons[ 'rightArm' ][ 'front' ][] = new Polygon( array(
1127 | $volume_points[ $i ][ $j ][ 4 * $hd_ratio ],
1128 | $volume_points[ $i + 1 ][ $j ][ 4 * $hd_ratio ],
1129 | $volume_points[ $i + 1 ][ $j + 1 ][ 4 * $hd_ratio ],
1130 | $volume_points[ $i ][ $j + 1 ][ 4 * $hd_ratio ]
1131 | ), imagecolorat( $img_png, 44 * $hd_ratio + $i, 20 * $hd_ratio + $j ) );
1132 | }
1133 | }
1134 | for ( $j = 0; $j < 12 * $hd_ratio; $j++ ) {
1135 | for ( $k = 0; $k < 4 * $hd_ratio; $k++ ) {
1136 | $this->polygons[ 'rightArm' ][ 'right' ][] = new Polygon( array(
1137 | $volume_points[ 0 ][ $j ][ $k ],
1138 | $volume_points[ 0 ][ $j ][ $k + 1 ],
1139 | $volume_points[ 0 ][ $j + 1 ][ $k + 1 ],
1140 | $volume_points[ 0 ][ $j + 1 ][ $k ]
1141 | ), imagecolorat( $img_png, 40 * $hd_ratio + $k, 20 * $hd_ratio + $j ) );
1142 | $this->polygons[ 'rightArm' ][ 'left' ][] = new Polygon( array(
1143 | $volume_points[ 4 * $hd_ratio ][ $j ][ $k ],
1144 | $volume_points[ 4 * $hd_ratio ][ $j ][ $k + 1 ],
1145 | $volume_points[ 4 * $hd_ratio ][ $j + 1 ][ $k + 1 ],
1146 | $volume_points[ 4 * $hd_ratio ][ $j + 1 ][ $k ]
1147 | ), imagecolorat( $img_png, ( 52 * $hd_ratio - 1 ) - $k, 20 * $hd_ratio + $j ) );
1148 | }
1149 | }
1150 | for ( $i = 0; $i < 4 * $hd_ratio; $i++ ) {
1151 | for ( $k = 0; $k < 4 * $hd_ratio; $k++ ) {
1152 | $this->polygons[ 'rightArm' ][ 'top' ][] = new Polygon( array(
1153 | $volume_points[ $i ][ 0 ][ $k ],
1154 | $volume_points[ $i + 1 ][ 0 ][ $k ],
1155 | $volume_points[ $i + 1 ][ 0 ][ $k + 1 ],
1156 | $volume_points[ $i ][ 0 ][ $k + 1 ]
1157 | ), imagecolorat( $img_png, 44 * $hd_ratio + $i, 16 * $hd_ratio + $k ) );
1158 | $this->polygons[ 'rightArm' ][ 'bottom' ][] = new Polygon( array(
1159 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k ],
1160 | $volume_points[ $i + 1 ][ 12 * $hd_ratio ][ $k ],
1161 | $volume_points[ $i + 1 ][ 12 * $hd_ratio ][ $k + 1 ],
1162 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k + 1 ]
1163 | ), imagecolorat( $img_png, 48 * $hd_ratio + $i, 16 * $hd_ratio + $k ) );
1164 | }
1165 | }
1166 | // LEFT ARM
1167 | $volume_points = array();
1168 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
1169 | for ( $j = 0; $j < 13 * $hd_ratio; $j++ ) {
1170 | if ( !isset( $volume_points[ $i ][ $j ][ 0 ] ) ) {
1171 | $volume_points[ $i ][ $j ][ 0 ] = new Point( array(
1172 | 'x' => $i + 8 * $hd_ratio,
1173 | 'y' => $j + 8 * $hd_ratio,
1174 | 'z' => 0
1175 | ) );
1176 | }
1177 | if ( !isset( $volume_points[ $i ][ $j ][ 4 * $hd_ratio ] ) ) {
1178 | $volume_points[ $i ][ $j ][ 4 * $hd_ratio ] = new Point( array(
1179 | 'x' => $i + 8 * $hd_ratio,
1180 | 'y' => $j + 8 * $hd_ratio,
1181 | 'z' => 4 * $hd_ratio
1182 | ) );
1183 | }
1184 | }
1185 | }
1186 | for ( $j = 0; $j < 13 * $hd_ratio; $j++ ) {
1187 | for ( $k = 0; $k < 5 * $hd_ratio; $k++ ) {
1188 | if ( !isset( $volume_points[ 0 ][ $j ][ $k ] ) ) {
1189 | $volume_points[ 0 ][ $j ][ $k ] = new Point( array(
1190 | 'x' => 0 + 8 * $hd_ratio,
1191 | 'y' => $j + 8 * $hd_ratio,
1192 | 'z' => $k
1193 | ) );
1194 | }
1195 | if ( !isset( $volume_points[ 8 * $hd_ratio ][ $j ][ $k ] ) ) {
1196 | $volume_points[ 4 * $hd_ratio ][ $j ][ $k ] = new Point( array(
1197 | 'x' => 4 * $hd_ratio + 8 * $hd_ratio,
1198 | 'y' => $j + 8 * $hd_ratio,
1199 | 'z' => $k
1200 | ) );
1201 | }
1202 | }
1203 | }
1204 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
1205 | for ( $k = 0; $k < 5 * $hd_ratio; $k++ ) {
1206 | if ( !isset( $volume_points[ $i ][ 0 ][ $k ] ) ) {
1207 | $volume_points[ $i ][ 0 ][ $k ] = new Point( array(
1208 | 'x' => $i + 8 * $hd_ratio,
1209 | 'y' => 0 + 8 * $hd_ratio,
1210 | 'z' => $k
1211 | ) );
1212 | }
1213 | if ( !isset( $volume_points[ $i ][ 12 * $hd_ratio ][ $k ] ) ) {
1214 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k ] = new Point( array(
1215 | 'x' => $i + 8 * $hd_ratio,
1216 | 'y' => 12 * $hd_ratio + 8 * $hd_ratio,
1217 | 'z' => $k
1218 | ) );
1219 | }
1220 | }
1221 | }
1222 | for ( $i = 0; $i < 4 * $hd_ratio; $i++ ) {
1223 | for ( $j = 0; $j < 12 * $hd_ratio; $j++ ) {
1224 | if($this->isNewSkinType) {
1225 | $color1 = imagecolorat( $img_png, 47 * $hd_ratio - $i, 52 * $hd_ratio + $j ); // from right to left
1226 | $color2 = imagecolorat( $img_png, 36 * $hd_ratio + $i , 52 * $hd_ratio + $j ); // from left to right
1227 | } else {
1228 | $color1 = imagecolorat( $img_png, ( 56 * $hd_ratio - 1 ) - ( ( 4 * $hd_ratio - 1 ) - $i ), 20 * $hd_ratio + $j );
1229 | $color2 = imagecolorat( $img_png, 44 * $hd_ratio + ( ( 4 * $hd_ratio - 1 ) - $i ), 20 * $hd_ratio + $j );
1230 | }
1231 |
1232 | $this->polygons[ 'leftArm' ][ 'back' ][] = new Polygon( array(
1233 | $volume_points[ $i ][ $j ][ 0 ],
1234 | $volume_points[ $i + 1 ][ $j ][ 0 ],
1235 | $volume_points[ $i + 1 ][ $j + 1 ][ 0 ],
1236 | $volume_points[ $i ][ $j + 1 ][ 0 ]
1237 | ), $color1 );
1238 | $this->polygons[ 'leftArm' ][ 'front' ][] = new Polygon( array(
1239 | $volume_points[ $i ][ $j ][ 4 * $hd_ratio ],
1240 | $volume_points[ $i + 1 ][ $j ][ 4 * $hd_ratio ],
1241 | $volume_points[ $i + 1 ][ $j + 1 ][ 4 * $hd_ratio ],
1242 | $volume_points[ $i ][ $j + 1 ][ 4 * $hd_ratio ]
1243 | ), $color2 );
1244 | }
1245 | }
1246 | for ( $j = 0; $j < 12 * $hd_ratio; $j++ ) {
1247 | for ( $k = 0; $k < 4 * $hd_ratio; $k++ ) {
1248 | if($this->isNewSkinType) {
1249 | $color1 = imagecolorat( $img_png, 32 * $hd_ratio + $k, 52 * $hd_ratio + $j ); // from left to right
1250 | $color2 = imagecolorat( $img_png, 43 * $hd_ratio - $k, 52 * $hd_ratio + $j ); // from right to left
1251 | } else {
1252 | $color1 = imagecolorat( $img_png, 40 * $hd_ratio + ( ( 4 * $hd_ratio - 1 ) - $k ), 20 * $hd_ratio + $j );
1253 | $color2 = imagecolorat( $img_png, ( 52 * $hd_ratio - 1 ) - ( ( 4 * $hd_ratio - 1 ) - $k ), 20 * $hd_ratio + $j );
1254 | }
1255 |
1256 | $this->polygons[ 'leftArm' ][ 'right' ][] = new Polygon( array(
1257 | $volume_points[ 0 ][ $j ][ $k ],
1258 | $volume_points[ 0 ][ $j ][ $k + 1 ],
1259 | $volume_points[ 0 ][ $j + 1 ][ $k + 1 ],
1260 | $volume_points[ 0 ][ $j + 1 ][ $k ]
1261 | ), $color1 );
1262 | $this->polygons[ 'leftArm' ][ 'left' ][] = new Polygon( array(
1263 | $volume_points[ 4 * $hd_ratio ][ $j ][ $k ],
1264 | $volume_points[ 4 * $hd_ratio ][ $j ][ $k + 1 ],
1265 | $volume_points[ 4 * $hd_ratio ][ $j + 1 ][ $k + 1 ],
1266 | $volume_points[ 4 * $hd_ratio ][ $j + 1 ][ $k ]
1267 | ), $color2 );
1268 | }
1269 | }
1270 | for ( $i = 0; $i < 4 * $hd_ratio; $i++ ) {
1271 | for ( $k = 0; $k < 4 * $hd_ratio; $k++ ) {
1272 | if($this->isNewSkinType) {
1273 | $color1 = imagecolorat( $img_png, 36 * $hd_ratio + $i, 48 * $hd_ratio + $k ); // from left to right
1274 | $color2 = imagecolorat( $img_png, 40 * $hd_ratio + $i, 48 * $hd_ratio + $k ); // from left to right
1275 | } else {
1276 | $color1 = imagecolorat( $img_png, 44 * $hd_ratio + ( ( 4 * $hd_ratio - 1 ) - $i ), 16 * $hd_ratio + $k );
1277 | $color2 = imagecolorat( $img_png, 48 * $hd_ratio + ( ( 4 * $hd_ratio - 1 ) - $i ), ( 20 * $hd_ratio - 1 ) - $k );
1278 | }
1279 |
1280 | $this->polygons[ 'leftArm' ][ 'top' ][] = new Polygon( array(
1281 | $volume_points[ $i ][ 0 ][ $k ],
1282 | $volume_points[ $i + 1 ][ 0 ][ $k ],
1283 | $volume_points[ $i + 1 ][ 0 ][ $k + 1 ],
1284 | $volume_points[ $i ][ 0 ][ $k + 1 ]
1285 | ), $color1 );
1286 | $this->polygons[ 'leftArm' ][ 'bottom' ][] = new Polygon( array(
1287 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k ],
1288 | $volume_points[ $i + 1 ][ 12 * $hd_ratio ][ $k ],
1289 | $volume_points[ $i + 1 ][ 12 * $hd_ratio ][ $k + 1 ],
1290 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k + 1 ]
1291 | ), $color2 );
1292 | }
1293 | }
1294 | // RIGHT LEG
1295 | $volume_points = array();
1296 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
1297 | for ( $j = 0; $j < 13 * $hd_ratio; $j++ ) {
1298 | if ( !isset( $volume_points[ $i ][ $j ][ 0 ] ) ) {
1299 | $volume_points[ $i ][ $j ][ 0 ] = new Point( array(
1300 | 'x' => $i,
1301 | 'y' => $j + 20 * $hd_ratio,
1302 | 'z' => 0
1303 | ) );
1304 | }
1305 | if ( !isset( $volume_points[ $i ][ $j ][ 4 * $hd_ratio ] ) ) {
1306 | $volume_points[ $i ][ $j ][ 4 * $hd_ratio ] = new Point( array(
1307 | 'x' => $i,
1308 | 'y' => $j + 20 * $hd_ratio,
1309 | 'z' => 4 * $hd_ratio
1310 | ) );
1311 | }
1312 | }
1313 | }
1314 | for ( $j = 0; $j < 13 * $hd_ratio; $j++ ) {
1315 | for ( $k = 0; $k < 5 * $hd_ratio; $k++ ) {
1316 | if ( !isset( $volume_points[ 0 ][ $j ][ $k ] ) ) {
1317 | $volume_points[ 0 ][ $j ][ $k ] = new Point( array(
1318 | 'x' => 0,
1319 | 'y' => $j + 20 * $hd_ratio,
1320 | 'z' => $k
1321 | ) );
1322 | }
1323 | if ( !isset( $volume_points[ 8 * $hd_ratio ][ $j ][ $k ] ) ) {
1324 | $volume_points[ 4 * $hd_ratio ][ $j ][ $k ] = new Point( array(
1325 | 'x' => 4 * $hd_ratio,
1326 | 'y' => $j + 20 * $hd_ratio,
1327 | 'z' => $k
1328 | ) );
1329 | }
1330 | }
1331 | }
1332 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
1333 | for ( $k = 0; $k < 5 * $hd_ratio; $k++ ) {
1334 | if ( !isset( $volume_points[ $i ][ 0 ][ $k ] ) ) {
1335 | $volume_points[ $i ][ 0 ][ $k ] = new Point( array(
1336 | 'x' => $i,
1337 | 'y' => 0 + 20 * $hd_ratio,
1338 | 'z' => $k
1339 | ) );
1340 | }
1341 | if ( !isset( $volume_points[ $i ][ 12 * $hd_ratio ][ $k ] ) ) {
1342 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k ] = new Point( array(
1343 | 'x' => $i,
1344 | 'y' => 12 * $hd_ratio + 20 * $hd_ratio,
1345 | 'z' => $k
1346 | ) );
1347 | }
1348 | }
1349 | }
1350 | for ( $i = 0; $i < 4 * $hd_ratio; $i++ ) {
1351 | for ( $j = 0; $j < 12 * $hd_ratio; $j++ ) {
1352 | $this->polygons[ 'rightLeg' ][ 'back' ][] = new Polygon( array(
1353 | $volume_points[ $i ][ $j ][ 0 ],
1354 | $volume_points[ $i + 1 ][ $j ][ 0 ],
1355 | $volume_points[ $i + 1 ][ $j + 1 ][ 0 ],
1356 | $volume_points[ $i ][ $j + 1 ][ 0 ]
1357 | ), imagecolorat( $img_png, ( 16 * $hd_ratio - 1 ) - $i, 20 * $hd_ratio + $j ) );
1358 | $this->polygons[ 'rightLeg' ][ 'front' ][] = new Polygon( array(
1359 | $volume_points[ $i ][ $j ][ 4 * $hd_ratio ],
1360 | $volume_points[ $i + 1 ][ $j ][ 4 * $hd_ratio ],
1361 | $volume_points[ $i + 1 ][ $j + 1 ][ 4 * $hd_ratio ],
1362 | $volume_points[ $i ][ $j + 1 ][ 4 * $hd_ratio ]
1363 | ), imagecolorat( $img_png, 4 * $hd_ratio + $i, 20 * $hd_ratio + $j ) );
1364 | }
1365 | }
1366 | for ( $j = 0; $j < 12 * $hd_ratio; $j++ ) {
1367 | for ( $k = 0; $k < 4 * $hd_ratio; $k++ ) {
1368 | $this->polygons[ 'rightLeg' ][ 'right' ][] = new Polygon( array(
1369 | $volume_points[ 0 ][ $j ][ $k ],
1370 | $volume_points[ 0 ][ $j ][ $k + 1 ],
1371 | $volume_points[ 0 ][ $j + 1 ][ $k + 1 ],
1372 | $volume_points[ 0 ][ $j + 1 ][ $k ]
1373 | ), imagecolorat( $img_png, 0 + $k, 20 * $hd_ratio + $j ) );
1374 | $this->polygons[ 'rightLeg' ][ 'left' ][] = new Polygon( array(
1375 | $volume_points[ 4 * $hd_ratio ][ $j ][ $k ],
1376 | $volume_points[ 4 * $hd_ratio ][ $j ][ $k + 1 ],
1377 | $volume_points[ 4 * $hd_ratio ][ $j + 1 ][ $k + 1 ],
1378 | $volume_points[ 4 * $hd_ratio ][ $j + 1 ][ $k ]
1379 | ), imagecolorat( $img_png, ( 12 * $hd_ratio - 1 ) - $k, 20 * $hd_ratio + $j ) );
1380 | }
1381 | }
1382 | for ( $i = 0; $i < 4 * $hd_ratio; $i++ ) {
1383 | for ( $k = 0; $k < 4 * $hd_ratio; $k++ ) {
1384 | $this->polygons[ 'rightLeg' ][ 'top' ][] = new Polygon( array(
1385 | $volume_points[ $i ][ 0 ][ $k ],
1386 | $volume_points[ $i + 1 ][ 0 ][ $k ],
1387 | $volume_points[ $i + 1 ][ 0 ][ $k + 1 ],
1388 | $volume_points[ $i ][ 0 ][ $k + 1 ]
1389 | ), imagecolorat( $img_png, 4 * $hd_ratio + $i, 16 * $hd_ratio + $k ) );
1390 | $this->polygons[ 'rightLeg' ][ 'bottom' ][] = new Polygon( array(
1391 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k ],
1392 | $volume_points[ $i + 1 ][ 12 * $hd_ratio ][ $k ],
1393 | $volume_points[ $i + 1 ][ 12 * $hd_ratio ][ $k + 1 ],
1394 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k + 1 ]
1395 | ), imagecolorat( $img_png, 8 * $hd_ratio + $i, 16 * $hd_ratio + $k ) );
1396 | }
1397 | }
1398 | // LEFT LEG
1399 | $volume_points = array();
1400 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
1401 | for ( $j = 0; $j < 13 * $hd_ratio; $j++ ) {
1402 | if ( !isset( $volume_points[ $i ][ $j ][ 0 ] ) ) {
1403 | $volume_points[ $i ][ $j ][ 0 ] = new Point( array(
1404 | 'x' => $i + 4 * $hd_ratio,
1405 | 'y' => $j + 20 * $hd_ratio,
1406 | 'z' => 0
1407 | ) );
1408 | }
1409 | if ( !isset( $volume_points[ $i ][ $j ][ 4 * $hd_ratio ] ) ) {
1410 | $volume_points[ $i ][ $j ][ 4 * $hd_ratio ] = new Point( array(
1411 | 'x' => $i + 4 * $hd_ratio,
1412 | 'y' => $j + 20 * $hd_ratio,
1413 | 'z' => 4 * $hd_ratio
1414 | ) );
1415 | }
1416 | }
1417 | }
1418 | for ( $j = 0; $j < 13 * $hd_ratio; $j++ ) {
1419 | for ( $k = 0; $k < 5 * $hd_ratio; $k++ ) {
1420 | if ( !isset( $volume_points[ 0 ][ $j ][ $k ] ) ) {
1421 | $volume_points[ 0 ][ $j ][ $k ] = new Point( array(
1422 | 'x' => 0 + 4 * $hd_ratio,
1423 | 'y' => $j + 20 * $hd_ratio,
1424 | 'z' => $k
1425 | ) );
1426 | }
1427 | if ( !isset( $volume_points[ 8 * $hd_ratio ][ $j ][ $k ] ) ) {
1428 | $volume_points[ 4 * $hd_ratio ][ $j ][ $k ] = new Point( array(
1429 | 'x' => 4 * $hd_ratio + 4 * $hd_ratio,
1430 | 'y' => $j + 20 * $hd_ratio,
1431 | 'z' => $k
1432 | ) );
1433 | }
1434 | }
1435 | }
1436 | for ( $i = 0; $i < 9 * $hd_ratio; $i++ ) {
1437 | for ( $k = 0; $k < 5 * $hd_ratio; $k++ ) {
1438 | if ( !isset( $volume_points[ $i ][ 0 ][ $k ] ) ) {
1439 | $volume_points[ $i ][ 0 ][ $k ] = new Point( array(
1440 | 'x' => $i + 4 * $hd_ratio,
1441 | 'y' => 0 + 20 * $hd_ratio,
1442 | 'z' => $k
1443 | ) );
1444 | }
1445 | if ( !isset( $volume_points[ $i ][ 12 * $hd_ratio ][ $k ] ) ) {
1446 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k ] = new Point( array(
1447 | 'x' => $i + 4 * $hd_ratio,
1448 | 'y' => 12 * $hd_ratio + 20 * $hd_ratio,
1449 | 'z' => $k
1450 | ) );
1451 | }
1452 | }
1453 | }
1454 | for ( $i = 0; $i < 4 * $hd_ratio; $i++ ) {
1455 | for ( $j = 0; $j < 12 * $hd_ratio; $j++ ) {
1456 | if($this->isNewSkinType) {
1457 | $color1 = imagecolorat( $img_png, 31 * $hd_ratio - $i, 52 * $hd_ratio + $j ); // from right to left
1458 | $color2 = imagecolorat( $img_png, 20 * $hd_ratio + $i , 52 * $hd_ratio + $j ); // from left to right
1459 | } else {
1460 | $color1 = imagecolorat( $img_png, ( 16 * $hd_ratio - 1 ) - ( ( 4 * $hd_ratio - 1 ) - $i ), 20 * $hd_ratio + $j );
1461 | $color2 = imagecolorat( $img_png, 4 * $hd_ratio + ( ( 4 * $hd_ratio - 1 ) - $i ), 20 * $hd_ratio + $j );
1462 | }
1463 |
1464 | $this->polygons[ 'leftLeg' ][ 'back' ][] = new Polygon( array(
1465 | $volume_points[ $i ][ $j ][ 0 ],
1466 | $volume_points[ $i + 1 ][ $j ][ 0 ],
1467 | $volume_points[ $i + 1 ][ $j + 1 ][ 0 ],
1468 | $volume_points[ $i ][ $j + 1 ][ 0 ]
1469 | ), $color1 );
1470 | $this->polygons[ 'leftLeg' ][ 'front' ][] = new Polygon( array(
1471 | $volume_points[ $i ][ $j ][ 4 * $hd_ratio ],
1472 | $volume_points[ $i + 1 ][ $j ][ 4 * $hd_ratio ],
1473 | $volume_points[ $i + 1 ][ $j + 1 ][ 4 * $hd_ratio ],
1474 | $volume_points[ $i ][ $j + 1 ][ 4 * $hd_ratio ]
1475 | ), $color2 );
1476 | }
1477 | }
1478 | for ( $j = 0; $j < 12 * $hd_ratio; $j++ ) {
1479 | for ( $k = 0; $k < 4 * $hd_ratio; $k++ ) {
1480 | if($this->isNewSkinType) {
1481 | $color1 = imagecolorat( $img_png, 16 * $hd_ratio + $k , 52 * $hd_ratio + $j ); // from left to right
1482 | $color2 = imagecolorat( $img_png, 27 * $hd_ratio - $k , 52 * $hd_ratio + $j ); // from right to left
1483 | } else {
1484 | $color1 = imagecolorat( $img_png, 0 + ( ( 4 * $hd_ratio - 1 ) - $k ), 20 * $hd_ratio + $j );
1485 | $color2 = imagecolorat( $img_png, ( 12 * $hd_ratio - 1 ) - ( ( 4 * $hd_ratio - 1 ) - $k ), 20 * $hd_ratio + $j );
1486 | }
1487 |
1488 | $this->polygons[ 'leftLeg' ][ 'right' ][] = new Polygon( array(
1489 | $volume_points[ 0 ][ $j ][ $k ],
1490 | $volume_points[ 0 ][ $j ][ $k + 1 ],
1491 | $volume_points[ 0 ][ $j + 1 ][ $k + 1 ],
1492 | $volume_points[ 0 ][ $j + 1 ][ $k ]
1493 | ), $color1 );
1494 | $this->polygons[ 'leftLeg' ][ 'left' ][] = new Polygon( array(
1495 | $volume_points[ 4 * $hd_ratio ][ $j ][ $k ],
1496 | $volume_points[ 4 * $hd_ratio ][ $j ][ $k + 1 ],
1497 | $volume_points[ 4 * $hd_ratio ][ $j + 1 ][ $k + 1 ],
1498 | $volume_points[ 4 * $hd_ratio ][ $j + 1 ][ $k ]
1499 | ), $color2 );
1500 | }
1501 | }
1502 | for ( $i = 0; $i < 4 * $hd_ratio; $i++ ) {
1503 | for ( $k = 0; $k < 4 * $hd_ratio; $k++ ) {
1504 | if($this->isNewSkinType) {
1505 | $color1 = imagecolorat( $img_png, 20 * $hd_ratio + $i , 48 * $hd_ratio + $k ); // from left to right
1506 | $color2 = imagecolorat( $img_png, 24 * $hd_ratio + $i , 48 * $hd_ratio + $k ); // from left to right
1507 | } else {
1508 | $color1 = imagecolorat( $img_png, 4 * $hd_ratio + ( ( 4 * $hd_ratio - 1 ) - $i ), 16 * $hd_ratio + $k );
1509 | $color2 = imagecolorat( $img_png, 8 * $hd_ratio + ( ( 4 * $hd_ratio - 1 ) - $i ), ( 20 * $hd_ratio - 1 ) - $k );
1510 | }
1511 |
1512 | $this->polygons[ 'leftLeg' ][ 'top' ][] = new Polygon( array(
1513 | $volume_points[ $i ][ 0 ][ $k ],
1514 | $volume_points[ $i + 1 ][ 0 ][ $k ],
1515 | $volume_points[ $i + 1 ][ 0 ][ $k + 1 ],
1516 | $volume_points[ $i ][ 0 ][ $k + 1 ]
1517 | ), $color1 );
1518 | $this->polygons[ 'leftLeg' ][ 'bottom' ][] = new Polygon( array(
1519 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k ],
1520 | $volume_points[ $i + 1 ][ 12 * $hd_ratio ][ $k ],
1521 | $volume_points[ $i + 1 ][ 12 * $hd_ratio ][ $k + 1 ],
1522 | $volume_points[ $i ][ 12 * $hd_ratio ][ $k + 1 ]
1523 | ), $color2 );
1524 | }
1525 | }
1526 | }
1527 | }
1528 |
1529 | /* Function rotates members
1530 | *
1531 | */
1532 | private function memberRotation() {
1533 | foreach ($this->polygons['head'] as $face ) {
1534 | foreach ( $face as $poly ) {
1535 | $poly->preProject( 4, 8, 2, $this->members_angles[ 'head' ][ 'cos_alpha' ], $this->members_angles[ 'head' ][ 'sin_alpha' ], $this->members_angles[ 'head' ][ 'cos_omega' ], $this->members_angles[ 'head' ][ 'sin_omega' ] );
1536 | }
1537 | }
1538 |
1539 | if ($this->display_hair) {
1540 | foreach ( $this->polygons[ 'helmet' ] as $face ) {
1541 | foreach ( $face as $poly ) {
1542 | $poly->preProject( 4, 8, 2, $this->members_angles[ 'head' ][ 'cos_alpha' ], $this->members_angles[ 'head' ][ 'sin_alpha' ], $this->members_angles[ 'head' ][ 'cos_omega' ], $this->members_angles[ 'head' ][ 'sin_omega' ] );
1543 | }
1544 | }
1545 | }
1546 |
1547 | if (!$this->head_only) {
1548 | foreach ( $this->polygons[ 'rightArm' ] as $face ) {
1549 | foreach ( $face as $poly ) {
1550 | $poly->preProject( -2, 8, 2, $this->members_angles[ 'rightArm' ][ 'cos_alpha' ], $this->members_angles[ 'rightArm' ][ 'sin_alpha' ], $this->members_angles[ 'rightArm' ][ 'cos_omega' ], $this->members_angles[ 'rightArm' ][ 'sin_omega' ] );
1551 | }
1552 | }
1553 | foreach ( $this->polygons[ 'leftArm' ] as $face ) {
1554 | foreach ( $face as $poly ) {
1555 | $poly->preProject( 10, 8, 2, $this->members_angles[ 'leftArm' ][ 'cos_alpha' ], $this->members_angles[ 'leftArm' ][ 'sin_alpha' ], $this->members_angles[ 'leftArm' ][ 'cos_omega' ], $this->members_angles[ 'leftArm' ][ 'sin_omega' ] );
1556 | }
1557 | }
1558 | foreach ( $this->polygons[ 'rightLeg' ] as $face ) {
1559 | foreach ( $face as $poly ) {
1560 | $poly->preProject( 2, 20, ( $this->members_angles[ 'rightLeg' ][ 'sin_alpha' ] < 0 ? 0 : 4 ), $this->members_angles[ 'rightLeg' ][ 'cos_alpha' ], $this->members_angles[ 'rightLeg' ][ 'sin_alpha' ], $this->members_angles[ 'rightLeg' ][ 'cos_omega' ], $this->members_angles[ 'rightLeg' ][ 'sin_omega' ] );
1561 | }
1562 | }
1563 | foreach ( $this->polygons[ 'leftLeg' ] as $face ) {
1564 | foreach ( $face as $poly ) {
1565 | $poly->preProject( 6, 20, ( $this->members_angles[ 'leftLeg' ][ 'sin_alpha' ] < 0 ? 0 : 4 ), $this->members_angles[ 'leftLeg' ][ 'cos_alpha' ], $this->members_angles[ 'leftLeg' ][ 'sin_alpha' ], $this->members_angles[ 'leftLeg' ][ 'cos_omega' ], $this->members_angles[ 'leftLeg' ][ 'sin_omega' ] );
1566 | }
1567 | }
1568 | }
1569 | }
1570 |
1571 | /* Create projection plan
1572 | *
1573 | */
1574 | private function createProjectionPlan() {
1575 | foreach ($this->polygons as $piece) {
1576 | foreach ($piece as $face) {
1577 | foreach ($face as $poly) {
1578 | if (!$poly->isProjected()) {
1579 | $poly->project();
1580 | }
1581 | }
1582 | }
1583 | }
1584 | }
1585 |
1586 | /* Function displays the image
1587 | *
1588 | */
1589 | private function displayImage($output) {
1590 | global $minX, $maxX, $minY, $maxY;
1591 | global $seconds_to_cache;
1592 |
1593 | $width = $maxX - $minX;
1594 | $height = $maxY - $minY;
1595 | $ratio = $this->ratio;
1596 | if ( $ratio < 2 ) {
1597 | $ratio = 2;
1598 | }
1599 |
1600 | if($this->aa === true) {
1601 | // double the ration for downscaling later (sort of AA)
1602 | $ratio = $ratio * 2;
1603 | }
1604 |
1605 | if ($seconds_to_cache > 0) {
1606 | $ts = gmdate( "D, d M Y H:i:s", time() + $seconds_to_cache ) . ' GMT';
1607 | if($output != 'return') {
1608 | header( 'Expires: ' . $ts );
1609 | header( 'Pragma: cache' );
1610 | header( 'Cache-Control: max-age=' . $seconds_to_cache );
1611 | }
1612 | }
1613 |
1614 | if ($this->format != 'svg') {
1615 | $srcWidth = $ratio * $width + 1;
1616 | $srcHeight = $ratio * $height + 1;
1617 | $realWidth = $srcWidth / 2;
1618 | $realHeight = $srcHeight / 2;
1619 |
1620 | $image = img::createEmptyCanvas($srcWidth, $srcHeight);
1621 | }
1622 |
1623 | $display_order = $this->getDisplayOrder();
1624 |
1625 | $imgOutput = '';
1626 | if($this->format == 'svg') {
1627 | $imgOutput .= '';
1646 | }
1647 |
1648 | if ($this->format !== 'svg') {
1649 | if($this->aa === true) {
1650 | // image normal size (sort of AA).
1651 | // resize the image down to it's normal size so it will be smoother
1652 | $destImage = img::createEmptyCanvas($realWidth, $realHeight);
1653 |
1654 | imagecopyresampled($destImage, $image, 0, 0, 0, 0, $realWidth, $realHeight, $srcWidth, $srcHeight);
1655 | $image = $destImage;
1656 | }
1657 |
1658 | $imgData = null;
1659 | if($this->format == 'base64') {
1660 | // output png;base64
1661 | ob_start();
1662 | imagepng($image);
1663 | $imgData = ob_get_contents();
1664 | ob_end_clean();
1665 | } else {
1666 | $imgOutput = $image;
1667 | }
1668 |
1669 | if($imgData !== null) {
1670 | $imgOutput = base64_encode($imgData);
1671 | imagedestroy($image);
1672 | }
1673 | }
1674 |
1675 | return $imgOutput;
1676 | }
1677 |
1678 | /* Function retuns display order
1679 | *
1680 | */
1681 | private function getDisplayOrder() {
1682 | $display_order = array();
1683 | if ( in_array( 'top', $this->front_faces ) ) {
1684 | if ( in_array( 'right', $this->front_faces ) ) {
1685 | $display_order[] = array('leftLeg' => $this->back_faces);
1686 | $display_order[] = array('leftLeg' => $this->visible_faces['leftLeg']['front']);
1687 | $display_order[] = array('rightLeg' => $this->back_faces);
1688 | $display_order[] = array('rightLeg' => $this->visible_faces['rightLeg']['front']);
1689 | $display_order[] = array('leftArm' => $this->back_faces);
1690 | $display_order[] = array('leftArm' => $this->visible_faces['leftArm']['front']);
1691 | $display_order[] = array('torso' => $this->back_faces);
1692 | $display_order[] = array('torso' => $this->visible_faces['torso']['front']);
1693 | $display_order[] = array('rightArm' => $this->back_faces);
1694 | $display_order[] = array('rightArm' => $this->visible_faces['rightArm']['front']);
1695 | } else {
1696 | $display_order[] = array('rightLeg' => $this->back_faces);
1697 | $display_order[] = array('rightLeg' => $this->visible_faces['rightLeg' ]['front']);
1698 | $display_order[] = array('leftLeg' => $this->back_faces);
1699 | $display_order[] = array('leftLeg' => $this->visible_faces['leftLeg']['front']);
1700 | $display_order[] = array('rightArm' => $this->back_faces);
1701 | $display_order[] = array('rightArm' => $this->visible_faces['rightArm']['front']);
1702 | $display_order[] = array('torso' => $this->back_faces);
1703 | $display_order[] = array('torso' => $this->visible_faces['torso']['front']);
1704 | $display_order[] = array('leftArm' => $this->back_faces);
1705 | $display_order[] = array('leftArm' => $this->visible_faces['leftArm']['front']);
1706 | }
1707 |
1708 | $display_order[] = array('helmet' => $this->back_faces);
1709 | $display_order[] = array('head' => $this->back_faces);
1710 | $display_order[] = array('head' => $this->visible_faces['head']['front']);
1711 | $display_order[] = array('helmet' => $this->visible_faces['head']['front']);
1712 | } else {
1713 | $display_order[] = array('helmet' => $this->back_faces);
1714 | $display_order[] = array('head' => $this->back_faces);
1715 | $display_order[] = array('head' => $this->visible_faces['head']['front']);
1716 | $display_order[] = array('helmet' => $this->visible_faces['head']['front']);
1717 |
1718 | if ( in_array( 'right', $this->front_faces ) ) {
1719 | $display_order[] = array('leftArm' => $this->back_faces);
1720 | $display_order[] = array('leftArm' => $this->visible_faces['leftArm']['front']);
1721 | $display_order[] = array('torso' => $this->back_faces);
1722 | $display_order[] = array('torso' => $this->visible_faces['torso']['front']);
1723 | $display_order[] = array('rightArm' => $this->back_faces);
1724 | $display_order[] = array('rightArm' => $this->visible_faces['rightArm']['front']);
1725 | $display_order[] = array('leftLeg' => $this->back_faces);
1726 | $display_order[] = array('leftLeg' => $this->visible_faces['leftLeg' ]['front']);
1727 | $display_order[] = array('rightLeg' => $this->back_faces);
1728 | $display_order[] = array('rightLeg' => $this->visible_faces['rightLeg']['front']);
1729 | } else {
1730 | $display_order[] = array('rightArm' => $this->back_faces);
1731 | $display_order[] = array('rightArm' => $this->visible_faces['rightArm']['front']);
1732 | $display_order[] = array('torso' => $this->back_faces);
1733 | $display_order[] = array('torso' => $this->visible_faces['torso']['front']);
1734 | $display_order[] = array('leftArm' => $this->back_faces);
1735 | $display_order[] = array('leftArm' => $this->visible_faces['leftArm']['front']);
1736 | $display_order[] = array('rightLeg' => $this->back_faces);
1737 | $display_order[] = array('rightLeg' => $this->visible_faces['rightLeg']['front']);
1738 | $display_order[] = array('leftLeg' => $this->back_faces);
1739 | $display_order[] = array('leftLeg' => $this->visible_faces['leftLeg']['front']);
1740 | }
1741 | }
1742 |
1743 | return $display_order;
1744 | }
1745 | }
1746 |
1747 | /* Img class
1748 | *
1749 | * Handels image related things
1750 | */
1751 | class img {
1752 | private function __construct() {
1753 | }
1754 |
1755 | /* Function creates a blank canvas
1756 | * with transparancy with the size of the
1757 | * given image.
1758 | *
1759 | * Espects canvas with and canvast height.
1760 | * Returns a empty canvas.
1761 | */
1762 | public static function createEmptyCanvas($w, $h) {
1763 | $dst = imagecreatetruecolor($w, $h);
1764 | imagesavealpha($dst, true);
1765 | $trans_colour = imagecolorallocatealpha($dst, 255, 255, 255, 127);
1766 | imagefill($dst, 0, 0, $trans_colour);
1767 |
1768 | return $dst;
1769 | }
1770 |
1771 | /* Function converts a non true color image to
1772 | * true color. This fixes the dark blue skins.
1773 | *
1774 | * Espects an image.
1775 | * Returns a true color image.
1776 | */
1777 | public static function convertToTrueColor($img) {
1778 | if(imageistruecolor($img)) {
1779 | return $img;
1780 | }
1781 |
1782 | $dst = img::createEmptyCanvas(imagesx($img), imagesy($img));
1783 |
1784 | imagecopy($dst, $img, 0, 0, 0, 0, imagesx($img), imagesy($img));
1785 | imagedestroy($img);
1786 |
1787 | return $dst;
1788 | }
1789 | }
1790 |
1791 | /* Point Class
1792 | *
1793 | */
1794 | class Point {
1795 | private $_originCoord;
1796 | private $_destCoord = array();
1797 | private $_isProjected = false;
1798 | private $_isPreProjected = false;
1799 |
1800 | public function __construct( $originCoord ) {
1801 | if ( is_array( $originCoord ) && count( $originCoord ) == 3 ) {
1802 | $this->_originCoord = array(
1803 | 'x' => ( isset( $originCoord[ 'x' ] ) ? $originCoord[ 'x' ] : 0 ),
1804 | 'y' => ( isset( $originCoord[ 'y' ] ) ? $originCoord[ 'y' ] : 0 ),
1805 | 'z' => ( isset( $originCoord[ 'z' ] ) ? $originCoord[ 'z' ] : 0 )
1806 | );
1807 | } else {
1808 | $this->_originCoord = array(
1809 | 'x' => 0,
1810 | 'y' => 0,
1811 | 'z' => 0
1812 | );
1813 | }
1814 | }
1815 |
1816 | public function project() {
1817 | global $cos_alpha, $sin_alpha, $cos_omega, $sin_omega;
1818 | global $minX, $maxX, $minY, $maxY;
1819 |
1820 | // 1, 0, 1, 0
1821 | $x = $this->_originCoord['x'];
1822 | $y = $this->_originCoord['y'];
1823 | $z = $this->_originCoord['z'];
1824 | $this->_destCoord['x'] = $x * $cos_omega + $z * $sin_omega;
1825 | $this->_destCoord['y'] = $x * $sin_alpha * $sin_omega + $y * $cos_alpha - $z * $sin_alpha * $cos_omega;
1826 | $this->_destCoord['z'] = -$x * $cos_alpha * $sin_omega + $y * $sin_alpha + $z * $cos_alpha * $cos_omega;
1827 | $this->_isProjected = true;
1828 | $minX = min($minX, $this->_destCoord['x']);
1829 | $maxX = max($maxX, $this->_destCoord['x']);
1830 | $minY = min($minY, $this->_destCoord['y']);
1831 | $maxY = max($maxY, $this->_destCoord['y']);
1832 | }
1833 |
1834 | public function preProject( $dx, $dy, $dz, $cos_alpha, $sin_alpha, $cos_omega, $sin_omega ) {
1835 | if ( !$this->_isPreProjected ) {
1836 | $x = $this->_originCoord[ 'x' ] - $dx;
1837 | $y = $this->_originCoord[ 'y' ] - $dy;
1838 | $z = $this->_originCoord[ 'z' ] - $dz;
1839 | $this->_originCoord[ 'x' ] = $x * $cos_omega + $z * $sin_omega + $dx;
1840 | $this->_originCoord[ 'y' ] = $x * $sin_alpha * $sin_omega + $y * $cos_alpha - $z * $sin_alpha * $cos_omega + $dy;
1841 | $this->_originCoord[ 'z' ] = -$x * $cos_alpha * $sin_omega + $y * $sin_alpha + $z * $cos_alpha * $cos_omega + $dz;
1842 | $this->_isPreProjected = true;
1843 | }
1844 | }
1845 |
1846 | public function getOriginCoord() {
1847 | return $this->_originCoord;
1848 | }
1849 |
1850 | public function getDestCoord() {
1851 | return $this->_destCoord;
1852 | }
1853 |
1854 | public function getDepth() {
1855 | if ( !$this->_isProjected ) {
1856 | $this->project();
1857 | }
1858 | return $this->_destCoord[ 'z' ];
1859 | }
1860 |
1861 | public function isProjected() {
1862 | return $this->_isProjected;
1863 | }
1864 | }
1865 |
1866 | /* Polygon Class
1867 | *
1868 | */
1869 | class Polygon {
1870 | private $_dots;
1871 | private $_colour;
1872 | private $_isProjected = false;
1873 | private $_face = 'w';
1874 | private $_faceDepth = 0;
1875 |
1876 | public function __construct( $dots, $colour ) {
1877 | $this->_dots = $dots;
1878 | $this->_colour = $colour;
1879 | $coord_0 = $dots[ 0 ]->getOriginCoord();
1880 | $coord_1 = $dots[ 1 ]->getOriginCoord();
1881 | $coord_2 = $dots[ 2 ]->getOriginCoord();
1882 | if ( $coord_0[ 'x' ] == $coord_1[ 'x' ] && $coord_1[ 'x' ] == $coord_2[ 'x' ] ) {
1883 | $this->_face = 'x';
1884 | $this->_faceDepth = $coord_0[ 'x' ];
1885 | } else if ( $coord_0[ 'y' ] == $coord_1[ 'y' ] && $coord_1[ 'y' ] == $coord_2[ 'y' ] ) {
1886 | $this->_face = 'y';
1887 | $this->_faceDepth = $coord_0[ 'y' ];
1888 | } else if ( $coord_0[ 'z' ] == $coord_1[ 'z' ] && $coord_1[ 'z' ] == $coord_2[ 'z' ] ) {
1889 | $this->_face = 'z';
1890 | $this->_faceDepth = $coord_0[ 'z' ];
1891 | }
1892 | }
1893 |
1894 | // never used
1895 | private function getFace() {
1896 | return $this->_face;
1897 | }
1898 |
1899 | // never used
1900 | private function getFaceDepth() {
1901 | if ( !$this->_isProjected ) {
1902 | $this->project();
1903 | }
1904 | return $this->_faceDepth;
1905 | }
1906 |
1907 | public function getSvgPolygon( $ratio ) {
1908 | $points_2d = '';
1909 | $r = ( $this->_colour >> 16 ) & 0xFF;
1910 | $g = ( $this->_colour >> 8 ) & 0xFF;
1911 | $b = $this->_colour & 0xFF;
1912 | $vR = ( 127 - ( ( $this->_colour & 0x7F000000 ) >> 24 ) ) / 127;
1913 | if ( $vR == 0 )
1914 | return '';
1915 | foreach ( $this->_dots as $dot ) {
1916 | $coord = $dot->getDestCoord();
1917 | $points_2d .= $coord[ 'x' ] * $ratio . ',' . $coord[ 'y' ] * $ratio . ' ';
1918 | }
1919 | $comment = '';
1920 | return $comment . '' . "\n";
1921 | }
1922 |
1923 | public function addPngPolygon( &$image, $minX, $minY, $ratio ) {
1924 | $points_2d = array();
1925 | $nb_points = 0;
1926 | $r = ( $this->_colour >> 16 ) & 0xFF;
1927 | $g = ( $this->_colour >> 8 ) & 0xFF;
1928 | $b = $this->_colour & 0xFF;
1929 | $vR = ( 127 - ( ( $this->_colour & 0x7F000000 ) >> 24 ) ) / 127;
1930 | if ( $vR == 0 )
1931 | return;
1932 | $same_plan_x = true;
1933 | $same_plan_y = true;
1934 | foreach ( $this->_dots as $dot ) {
1935 | $coord = $dot->getDestCoord();
1936 | if ( !isset( $coord_x ) )
1937 | $coord_x = $coord[ 'x' ];
1938 | if ( !isset( $coord_y ) )
1939 | $coord_y = $coord[ 'y' ];
1940 | if ( $coord_x != $coord[ 'x' ] )
1941 | $same_plan_x = false;
1942 | if ( $coord_y != $coord[ 'y' ] )
1943 | $same_plan_y = false;
1944 | $points_2d[] = ( $coord[ 'x' ] - $minX ) * $ratio;
1945 | $points_2d[] = ( $coord[ 'y' ] - $minY ) * $ratio;
1946 | $nb_points++;
1947 | }
1948 | if ( !( $same_plan_x || $same_plan_y ) ) {
1949 | $colour = imagecolorallocate( $image, $r, $g, $b );
1950 | imagefilledpolygon( $image, $points_2d, $nb_points, $colour );
1951 | }
1952 | }
1953 |
1954 | public function isProjected() {
1955 | return $this->_isProjected;
1956 | }
1957 |
1958 | public function project() {
1959 | foreach ( $this->_dots as &$dot ) {
1960 | if ( !$dot->isProjected() ) {
1961 | $dot->project();
1962 | }
1963 | }
1964 | $this->_isProjected = true;
1965 | }
1966 |
1967 | public function preProject( $dx, $dy, $dz, $cos_alpha, $sin_alpha, $cos_omega, $sin_omega ) {
1968 | foreach ( $this->_dots as &$dot ) {
1969 | $dot->preProject( $dx, $dy, $dz, $cos_alpha, $sin_alpha, $cos_omega, $sin_omega );
1970 | }
1971 | }
1972 | }
1973 | ?>
1974 |
--------------------------------------------------------------------------------