├── 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 .= ''; 1628 | } 1629 | 1630 | foreach ($display_order as $pieces) { 1631 | foreach ($pieces as $piece => $faces) { 1632 | foreach ($faces as $face) { 1633 | foreach ($this->polygons[$piece][$face] as $poly) { 1634 | if ($this->format == 'svg') { 1635 | $imgOutput .= $poly->getSvgPolygon(1); 1636 | } else { 1637 | $poly->addPngPolygon($image, $minX, $minY, $ratio); 1638 | } 1639 | } 1640 | } 1641 | } 1642 | } 1643 | 1644 | if($this->format == 'svg') { 1645 | $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 | --------------------------------------------------------------------------------