260 lines
8.4 KiB
PHP
260 lines
8.4 KiB
PHP
<?php
|
|
|
|
namespace swf2ass;
|
|
|
|
|
|
use swf2ass\actions\ActionList;
|
|
use swf2ass\actions\GoToFrameAction;
|
|
use swf2ass\actions\NextFrameAction;
|
|
use swf2ass\actions\PlayAction;
|
|
use swf2ass\actions\PreviousFrameAction;
|
|
use swf2ass\actions\StopAction;
|
|
|
|
class SWFTreeProcessor {
|
|
protected ViewLayout $layout;
|
|
|
|
protected ObjectCollection $objects;
|
|
protected ?array $tags;
|
|
protected int $index = 0;
|
|
|
|
protected int $frame;
|
|
|
|
protected ?ViewFrame $lastFrame = null;
|
|
protected bool $playing = true;
|
|
protected int $loops = 0;
|
|
|
|
public function __construct(int $objectId, ?array $tags, ?ObjectCollection $objects = null) {
|
|
$this->objects = $objects ?? new ObjectCollection();
|
|
$this->frame = 0;
|
|
$this->tags = $tags;
|
|
$this->layout = new ViewLayout($objectId, null);
|
|
}
|
|
|
|
public function getTags() : array{
|
|
return $this->tags;
|
|
}
|
|
|
|
public function getFrame(): int {
|
|
return $this->frame;
|
|
}
|
|
|
|
protected function next() {
|
|
++$this->index;
|
|
}
|
|
|
|
protected function current(): ?array {
|
|
return $this->tags[$this->index] ?? null;
|
|
}
|
|
|
|
public function getObjectCollection(): ObjectCollection {
|
|
return $this->objects;
|
|
}
|
|
|
|
protected function process(ActionList $actionList): ?string {
|
|
$node = $this->current();
|
|
if ($node === null) {
|
|
return null;
|
|
}
|
|
|
|
switch ($node["tagType"]) {
|
|
case "DefineMorphShape":
|
|
case "DefineMorphShape2":
|
|
if($this->loops > 0){
|
|
break;
|
|
}
|
|
$shape = MorphShapeDefinition::fromArray($node);
|
|
$this->objects->add($shape);
|
|
break;
|
|
case "DefineShape":
|
|
case "DefineShape2":
|
|
case "DefineShape3":
|
|
case "DefineShape4":
|
|
case "DefineShape5":
|
|
if($this->loops > 0){
|
|
break;
|
|
}
|
|
$shape = ShapeDefinition::fromArray($node);
|
|
$this->objects->add($shape);
|
|
break;
|
|
case "DefineSprite":
|
|
|
|
if($this->loops > 0){
|
|
break;
|
|
}
|
|
$objectID = $node["spriteId"];
|
|
$framesCount = $node["frameCount"];
|
|
|
|
$sprite = new SpriteDefinition($objectID, new SWFTreeProcessor($objectID, $node["tags"], $this->objects));
|
|
|
|
$this->objects->add($sprite);
|
|
break;
|
|
case "DefineBitsLossless":
|
|
case "DefineBitsLossless2":
|
|
if($this->loops > 0){
|
|
break;
|
|
}
|
|
break; //TODO
|
|
$bitmap = BitmapDefinition::fromArray($node);
|
|
|
|
$this->objects->add($bitmap);
|
|
break;
|
|
case "DefineBitsJPEG2":
|
|
case "DefineBitsJPEG3":
|
|
if($this->loops > 0){
|
|
break;
|
|
}
|
|
break; //TODO
|
|
$bitmap = JPEGBitmapDefinition::fromArray($node);
|
|
$this->objects->add($bitmap);
|
|
break;
|
|
case "RemoveObject":
|
|
case "RemoveObject2":
|
|
$this->layout->remove($node["depth"]);
|
|
break;
|
|
case "PlaceObject2":
|
|
case "PlaceObject3":
|
|
$depth = $node["depth"];
|
|
|
|
$objectID = $node["characterId"] ?? null;
|
|
$clipDepth = $node["clipDepth"] ?? null;
|
|
|
|
$replace = $node["placeFlagMove"] === 1;
|
|
|
|
$object = $objectID === null ? $this->layout->get($depth) : $this->objects->get($objectID);
|
|
if ($object === null) {
|
|
var_dump("Object oid:$objectID depth:$depth not found");
|
|
/*if($replace){
|
|
$this->layout->remove($depth);
|
|
}*/
|
|
//TODO: insert bogus one
|
|
$this->layout->remove($depth);
|
|
break;
|
|
}
|
|
|
|
$ratio = isset($node["ratio"]) ? $node["ratio"] / 65535 : null;
|
|
|
|
|
|
$transform = isset($node["matrix"]) ? MatrixTransform::fromSWFArray($node["matrix"]) : null;
|
|
|
|
|
|
|
|
$colorTransform = isset($node["colorTransform"]) ? ColorTransform::fromArray($node["colorTransform"]) : null;
|
|
|
|
$currentObject = $this->layout->get($depth);
|
|
|
|
|
|
if ($replace and $currentObject !== null and $currentObject->getObjectId() === $object->getObjectId()) {
|
|
if ($transform !== null) {
|
|
$currentObject->setMatrixTransform($transform);
|
|
}
|
|
if ($colorTransform !== null) {
|
|
$currentObject->setColorTransform($colorTransform);
|
|
}
|
|
if($ratio !== null){
|
|
$currentObject->setRatio($ratio);
|
|
}
|
|
break;
|
|
}
|
|
|
|
$view = $clipDepth !== null ? new ClippingViewLayout($clipDepth, $objectID, $object->getSafeObject(), $this->layout) : new ViewLayout($objectID, $object->getSafeObject(), $this->layout);
|
|
$view->setMatrixTransform($transform);
|
|
$view->setColorTransform($colorTransform);
|
|
$view->setRatio($ratio);
|
|
|
|
if ($replace) {
|
|
$this->layout->replace($depth, $view);
|
|
} else {
|
|
$this->layout->place($depth, $view);
|
|
}
|
|
|
|
break;
|
|
case "ShowFrame":
|
|
break;
|
|
case "EndTag":
|
|
break;
|
|
case "DoAction":
|
|
foreach ($node["actions"] as $action){
|
|
switch ($action["actionName"]){
|
|
case "ActionStop":
|
|
$actionList->actions[] = new StopAction();
|
|
break;
|
|
case "ActionPlay":
|
|
$actionList->actions[] = new PlayAction();
|
|
break;
|
|
/*case "ActionGotoFrame":
|
|
$actionList->actions[] = new GoToFrameAction($action["actionData"]["frame"]);
|
|
break;*/
|
|
case "ActionNextFrame":
|
|
$actionList->actions[] = new NextFrameAction();
|
|
break;
|
|
/*case "ActionPreviousFrame":
|
|
$actionList->actions[] = new PreviousFrameAction();
|
|
break;*/
|
|
case null:
|
|
break;
|
|
default:
|
|
var_dump($action);
|
|
var_dump("NOT IMPLEMENTED: ACTION " . $action["actionName"]);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
//TODO
|
|
var_dump($node["tagType"]);
|
|
}
|
|
|
|
return $node["tagType"];
|
|
}
|
|
|
|
public function getViewLayout(): ViewLayout {
|
|
return $this->layout;
|
|
}
|
|
|
|
public function isPlaying() : bool{
|
|
return $this->playing;
|
|
}
|
|
|
|
public function getLoops() : int{
|
|
return $this->loops;
|
|
}
|
|
|
|
public function nextFrame(): ?ViewFrame {
|
|
$actions = new ActionList();
|
|
if(!$this->playing){
|
|
return $this->lastFrame;
|
|
}
|
|
while (($nodeName = $this->process($actions)) !== null) {
|
|
$this->next();
|
|
|
|
if ($nodeName === "ShowFrame") {
|
|
break;
|
|
} else if ($nodeName === "End" and $this->frame === 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($nodeName === null) { //Loop again
|
|
$this->loops++;
|
|
$this->frame = 0;
|
|
$this->index = 0;
|
|
$this->layout = new ViewLayout($this->layout->getObjectId(), null);
|
|
return $this->lastFrame !== null ? $this->nextFrame() : null;
|
|
}
|
|
|
|
++$this->frame;
|
|
|
|
$frame = $this->lastFrame = $this->layout->nextFrame($actions);
|
|
|
|
foreach ($actions->actions as $action){
|
|
if($action instanceof StopAction){
|
|
$this->playing = false;
|
|
}else if($action instanceof PlayAction){
|
|
$this->playing = true;
|
|
}else if($action instanceof NextFrameAction){
|
|
return $this->nextFrame();
|
|
}
|
|
}
|
|
return $frame;
|
|
}
|
|
} |