175 lines
6 KiB
PHP
175 lines
6 KiB
PHP
<?php
|
|
|
|
namespace swf2ass;
|
|
|
|
|
|
class ShapeConverter {
|
|
|
|
private StyleList $styles;
|
|
|
|
private ?ActivePath $fill_style0 = null;
|
|
private ?ActivePath $fill_style1 = null;
|
|
private ?ActivePath $line_style = null;
|
|
|
|
private Vector2 $position;
|
|
|
|
private PendingPathMap $fills;
|
|
private PendingPathMap $strokes;
|
|
|
|
public DrawPathList $commands;
|
|
|
|
|
|
public function __construct(\DOMElement $element, StyleList $currentStyles) {
|
|
$this->styles = $currentStyles;
|
|
$this->position = new Vector2(0, 0);
|
|
$this->fills = new PendingPathMap();
|
|
$this->strokes = new PendingPathMap();
|
|
$this->commands = new DrawPathList([]);
|
|
|
|
foreach ($element->getElementsByTagName("edges")->item(0)->childNodes as $node) {
|
|
if ($node->nodeName === "ShapeSetup") {
|
|
//Utils::dump_element($node);
|
|
if ($node->hasAttribute("x")) {
|
|
$move = MoveRecord::fromXML($node, $this->position);
|
|
$this->position = $move->coord;
|
|
|
|
$this->flush_paths();
|
|
}
|
|
|
|
if ($node->hasChildNodes()) {
|
|
$this->flush_layer();
|
|
|
|
$this->styles = StyleList::fromXML($node->getElementsByTagName("styles")->item(0)->getElementsByTagName("StyleList")->item(0));
|
|
}
|
|
|
|
|
|
if ($node->hasAttribute("fillStyle1")) {
|
|
if ($this->fill_style1 !== null) {
|
|
$this->fills->merge_path($this->fill_style1, true);
|
|
}
|
|
|
|
$id = (int)$node->getAttribute("fillStyle1");
|
|
|
|
|
|
$this->fill_style1 = $id > 0 ? new ActivePath($id, $this->position) : null;
|
|
}
|
|
|
|
if ($node->hasAttribute("fillStyle0")) {
|
|
if ($this->fill_style0 !== null) {
|
|
if (!$this->fill_style0->segment->is_empty()) {
|
|
$this->fill_style0->flip();
|
|
$this->fills->merge_path($this->fill_style0, true);
|
|
}
|
|
}
|
|
|
|
$id = (int)$node->getAttribute("fillStyle0");
|
|
$this->fill_style0 = $id > 0 ? new ActivePath($id, $this->position) : null;
|
|
}
|
|
|
|
if ($node->hasAttribute("lineStyle")) {
|
|
if ($this->line_style !== null) {
|
|
$this->strokes->merge_path($this->line_style, false);
|
|
}
|
|
|
|
$id = (int)$node->getAttribute("lineStyle");
|
|
|
|
|
|
$this->line_style = $id > 0 ? new ActivePath($id, $this->position) : null;
|
|
}
|
|
} else if ($node->nodeName === "LineTo") {
|
|
$line = LineRecord::fromXML($node, $this->position);
|
|
|
|
$this->visit_point($line->coord, false);
|
|
|
|
$this->position = $line->coord;
|
|
} else if ($node->nodeName === "CurveTo") {
|
|
$curve = QuadraticCurveRecord::fromXML($node, $this->position);
|
|
|
|
$this->visit_point($curve->control, true);
|
|
$this->visit_point($curve->anchor, false);
|
|
|
|
$this->position = $curve->anchor;
|
|
}
|
|
}
|
|
|
|
$this->flush_layer();
|
|
}
|
|
|
|
public function visit_point(Vector2 $coordinate, bool $isBezierControlPoint) {
|
|
$point = new VisitedPoint($coordinate, $isBezierControlPoint);
|
|
if ($this->fill_style0 !== null) {
|
|
$this->fill_style0->add_point($point);
|
|
}
|
|
if ($this->fill_style1 !== null) {
|
|
$this->fill_style1->add_point($point);
|
|
}
|
|
if ($this->line_style !== null) {
|
|
$this->line_style->add_point($point);
|
|
}
|
|
}
|
|
|
|
public function flush_paths() {
|
|
if ($this->fill_style1 !== null) {
|
|
$this->fills->merge_path($this->fill_style1, true);
|
|
$this->fill_style1 = new ActivePath($this->fill_style1->style, $this->position);
|
|
}
|
|
|
|
if ($this->fill_style0 !== null) {
|
|
if (!$this->fill_style0->segment->is_empty()) {
|
|
$this->fill_style0->flip();
|
|
$this->fills->merge_path($this->fill_style0, true);
|
|
}
|
|
$this->fill_style0 = new ActivePath($this->fill_style0->style, $this->position);
|
|
}
|
|
if ($this->line_style !== null) {
|
|
$this->strokes->merge_path($this->line_style, false);
|
|
$this->line_style = new ActivePath($this->line_style->style, $this->position);
|
|
}
|
|
}
|
|
|
|
public function flush_layer() {
|
|
$this->flush_paths();
|
|
|
|
$this->fill_style0 = null;
|
|
$this->fill_style1 = null;
|
|
$this->line_style = null;
|
|
|
|
foreach ($this->fills->map as $styleId => $path) {
|
|
assert($styleId > 0 && $styleId < count($this->styles->fillStyles)); // ?????
|
|
|
|
$style = $this->styles->getFillStyle($styleId - 1);
|
|
|
|
if ($style === null) {
|
|
var_dump($this->styles);
|
|
var_dump($styleId);
|
|
}
|
|
|
|
$this->commands->commands[] = DrawPath::fill($style, $path->getShape());
|
|
}
|
|
$this->fills->map = [];
|
|
|
|
foreach ($this->strokes->map as $styleId => $path) {
|
|
assert($styleId > 0 && $styleId < count($this->styles->lineStyles)); // ?????
|
|
|
|
$style = $this->styles->getLineStyle($styleId - 1);
|
|
|
|
|
|
foreach ($path->segments as $segment) {
|
|
$segmentStyle = $style;
|
|
//Close non-closed segments by double drawing backwards
|
|
if (!$segment->is_closed()) {
|
|
$other = clone $segment;
|
|
$other->flip();
|
|
$segment->merge($other);
|
|
|
|
//Reduce width of line style to account for double border
|
|
$segmentStyle = clone $style;
|
|
$segmentStyle->width /= 2;
|
|
}
|
|
|
|
$this->commands->commands[] = DrawPath::stroke($segmentStyle, $segment->getShape(), $segment->is_closed());
|
|
}
|
|
}
|
|
$this->strokes->map = [];
|
|
}
|
|
} |