105 lines
3.6 KiB
PHP
105 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace swf2ass;
|
|
|
|
|
|
abstract class Utils {
|
|
|
|
|
|
static function padHex($h, $l = 2) {
|
|
return str_pad($h, $l, "0", STR_PAD_LEFT);
|
|
}
|
|
|
|
static function bin2binary($bin) {
|
|
return gmp_strval(gmp_init(bin2hex($bin), 16), 2);
|
|
}
|
|
|
|
static function binary2dec($bin) {
|
|
return gmp_intval(gmp_init($bin, 2));
|
|
}
|
|
|
|
public static function lerpInteger(int $start, int $end, float $ratio): int {
|
|
return $start + ($end - $start) * $ratio;
|
|
}
|
|
|
|
public static function lerpFloat(float $start, float $end, float $ratio): float {
|
|
return $start + ($end - $start) * $ratio;
|
|
}
|
|
|
|
public static function lerpVector2(Vector2 $start, Vector2 $end, float $ratio): Vector2 {
|
|
return $start->add($end->sub($start)->multiply($ratio));
|
|
}
|
|
|
|
public static function lerpColor(Color $start, Color $end, float $ratio): Color {
|
|
return new Color(self::lerpInteger($start->r, $end->r, $ratio), self::lerpInteger($start->g, $end->g, $ratio), self::lerpInteger($start->b, $end->b, $ratio), self::lerpInteger($start->alpha, $end->alpha, $ratio));
|
|
}
|
|
|
|
/**
|
|
* @param Gradient $gradient
|
|
* @param int $slices
|
|
* @return \Iterator<GradientSlice>|GradientSlice[]
|
|
*/
|
|
public static function lerpGradient(Gradient $gradient, int $slices = Gradient::AUTO_SLICES): \Iterator{
|
|
$items = $gradient->getItems();
|
|
|
|
//TODO: spread modes
|
|
$first = reset($items);
|
|
$last = end($items);
|
|
|
|
if($first->ratio !== 0){
|
|
$first = clone $first;
|
|
$first->ratio = 0;
|
|
array_unshift($items, $first);
|
|
}
|
|
if($last->ratio !== 255){
|
|
$last = clone $last;
|
|
$last->ratio = 255;
|
|
array_push($items, $last);
|
|
}
|
|
|
|
$prevItem = null;
|
|
foreach ($items as $item){
|
|
if($prevItem !== null){
|
|
if($gradient->getInterpolationMode() === Gradient::INTERPOLATE_LINEAR_RGB){
|
|
$prevColor = $prevItem->color->toLinearRGB();
|
|
$currentColor = $item->color->toLinearRGB();
|
|
}else{
|
|
$prevColor = $prevItem->color;
|
|
$currentColor = $item->color;
|
|
}
|
|
|
|
$maxColorDistance = max(abs($prevColor->r - $currentColor->r), abs($prevColor->g - $currentColor->g), abs($prevColor->b - $currentColor->b), abs($prevColor->alpha - $currentColor->alpha));
|
|
$prevPosition = $prevItem->ratio;
|
|
$currentPosition = $item->ratio;
|
|
$distance = abs($prevPosition - $currentPosition);
|
|
|
|
if($maxColorDistance < Constants::EPSILON){
|
|
$partitions = 1;
|
|
}else if($slices === Gradient::AUTO_SLICES){
|
|
$partitions = min(255 / (count($items) + 1), max(1, ceil($maxColorDistance)));
|
|
}else{
|
|
$partitions = ($distance / 255) * $slices;
|
|
}
|
|
$partitions = max(1, ceil($partitions));
|
|
|
|
|
|
$fromPos = $prevPosition;
|
|
for($i = 1; $i <= $partitions; ++$i){
|
|
$ratio = $i / $partitions;
|
|
$color = Utils::lerpColor($prevColor, $currentColor, $ratio);
|
|
|
|
if($gradient->getInterpolationMode() === Gradient::INTERPOLATE_LINEAR_RGB){
|
|
$color = $color->tosRGB();
|
|
}
|
|
|
|
$toPos = Utils::lerpFloat($prevPosition, $currentPosition, $ratio);
|
|
|
|
yield new GradientSlice($color, $fromPos, $toPos);
|
|
|
|
$fromPos = $toPos;
|
|
}
|
|
}
|
|
$prevItem = $item;
|
|
}
|
|
}
|
|
} |