"simple" implementation of Actions
This commit is contained in:
parent
32980ce1c0
commit
54ed3bc110
|
@ -1,9 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace swf2ass;
|
||||
|
||||
|
||||
class ActionList {
|
||||
|
||||
|
||||
}
|
|
@ -91,4 +91,8 @@ class BitmapDefinition implements ObjectDefinition {
|
|||
return (string)$im;
|
||||
}
|
||||
|
||||
public function getSafeObject() : BitmapDefinition{
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
namespace swf2ass;
|
||||
|
||||
|
||||
use swf2ass\actions\ActionList;
|
||||
|
||||
class ClippingViewLayout extends ViewLayout {
|
||||
private int $clipDepth;
|
||||
|
||||
|
|
|
@ -9,8 +9,6 @@ class MorphShapeDefinition implements ObjectDefinition {
|
|||
public DrawPathList $startShapeList;
|
||||
public DrawPathList $endShapeList;
|
||||
|
||||
public float $ratio = 0;
|
||||
|
||||
|
||||
public function __construct(int $id, Rectangle $startBounds, Rectangle $endBounds, DrawPathList $startShapeList, DrawPathList $endShapeList) {
|
||||
$this->id = $id;
|
||||
|
@ -185,4 +183,8 @@ class MorphShapeDefinition implements ObjectDefinition {
|
|||
|
||||
return new MorphShapeDefinition($element["characterId"], Rectangle::fromArray($element["startBounds"]), Rectangle::fromArray($element["endBounds"]), $start, $end);
|
||||
}
|
||||
|
||||
public function getSafeObject() : MorphShapeDefinition{
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -6,5 +6,7 @@ interface ObjectDefinition {
|
|||
|
||||
public function getObjectId(): int;
|
||||
|
||||
public function getSafeObject() : ObjectDefinition;
|
||||
|
||||
public function getShapeList(float $ratio): DrawPathList;
|
||||
}
|
|
@ -4,6 +4,7 @@ namespace swf2ass;
|
|||
|
||||
|
||||
use swf\SWF;
|
||||
use swf2ass\actions\ActionList;
|
||||
|
||||
class SWFProcessor extends SWFTreeProcessor {
|
||||
const BACKGROUND_OBJECT_ID = 0;
|
||||
|
@ -55,7 +56,7 @@ class SWFProcessor extends SWFTreeProcessor {
|
|||
return $this->audio;
|
||||
}
|
||||
|
||||
protected function process(): ?string {
|
||||
protected function process(ActionList $actionList): ?string {
|
||||
$node = $this->current();
|
||||
if ($node === null) {
|
||||
return null;
|
||||
|
@ -71,6 +72,8 @@ class SWFProcessor extends SWFTreeProcessor {
|
|||
$this->audio = AudioStream::fromSoundStreamHeadTag($node);
|
||||
return $node["tagType"];
|
||||
case "DefineSound":
|
||||
$this->audio = new AudioStream(0, 0, 0, 0);
|
||||
$this->audio->setStartFrame($this->getFrame());
|
||||
//TODO $this->audio = (object)["node" => $node, "start" => $this->getFrame(), "content" => []];
|
||||
return $node["tagType"];
|
||||
case "SoundStreamBlock":
|
||||
|
@ -83,17 +86,20 @@ class SWFProcessor extends SWFTreeProcessor {
|
|||
return $node["tagType"];
|
||||
}
|
||||
|
||||
return parent::process();
|
||||
return parent::process($actionList);
|
||||
}
|
||||
|
||||
public function nextFrameOutput(): ?FrameInformation {
|
||||
$actions = $actions ?? new ActionList();
|
||||
$frame = $this->nextFrame($actions);
|
||||
$frame = $this->nextFrame();
|
||||
|
||||
if ($frame === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if(!$this->isPlaying() and ($this->audio === null or $this->audio->getStartFrame() === null)){ //Force play till finding audio
|
||||
$this->playing = true;
|
||||
}
|
||||
|
||||
//TODO: actions?
|
||||
|
||||
$frame->addChild(self::BACKGROUND_OBJECT_DEPTH, new ViewFrame(self::BACKGROUND_OBJECT_ID, new DrawPathList([DrawPath::fill($this->background, new Shape($this->getViewPort()->draw()))])));
|
||||
|
|
|
@ -3,6 +3,13 @@
|
|||
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;
|
||||
|
||||
|
@ -12,6 +19,10 @@ class SWFTreeProcessor {
|
|||
|
||||
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;
|
||||
|
@ -19,6 +30,10 @@ class SWFTreeProcessor {
|
|||
$this->layout = new ViewLayout($objectId, null);
|
||||
}
|
||||
|
||||
public function getTags() : array{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
public function getFrame(): int {
|
||||
return $this->frame;
|
||||
}
|
||||
|
@ -35,7 +50,7 @@ class SWFTreeProcessor {
|
|||
return $this->objects;
|
||||
}
|
||||
|
||||
protected function process(): ?string {
|
||||
protected function process(ActionList $actionList): ?string {
|
||||
$node = $this->current();
|
||||
if ($node === null) {
|
||||
return null;
|
||||
|
@ -59,22 +74,8 @@ class SWFTreeProcessor {
|
|||
|
||||
$objectID = $node["spriteId"];
|
||||
$framesCount = $node["frameCount"];
|
||||
$spriteTree = new SWFTreeProcessor($objectID, $node["tags"], $this->objects);
|
||||
$actions = new ActionList();
|
||||
|
||||
/** @var ViewFrame[] $frames */
|
||||
$frames = [];
|
||||
while (($frame = $spriteTree->nextFrame($actions)) !== null) {
|
||||
$frames[] = $frame;
|
||||
}
|
||||
|
||||
if(count($frames) === 0){
|
||||
var_dump($node);
|
||||
var_dump("sprite $objectID had no valid frames!");
|
||||
break;
|
||||
}
|
||||
|
||||
$sprite = new SpriteDefinition($objectID, $frames);
|
||||
$sprite = new SpriteDefinition($objectID, new SWFTreeProcessor($objectID, $node["tags"], $this->objects));
|
||||
|
||||
$this->objects->add($sprite);
|
||||
break;
|
||||
|
@ -140,7 +141,7 @@ class SWFTreeProcessor {
|
|||
break;
|
||||
}
|
||||
|
||||
$view = $clipDepth !== null ? new ClippingViewLayout($clipDepth, $objectID, $object, $this->layout, $ratio) : new ViewLayout($objectID, $object, $this->layout, $ratio);
|
||||
$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);
|
||||
|
@ -156,6 +157,33 @@ class SWFTreeProcessor {
|
|||
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"]);
|
||||
|
@ -168,8 +196,16 @@ class SWFTreeProcessor {
|
|||
return $this->layout;
|
||||
}
|
||||
|
||||
public function nextFrame(ActionList $actions): ?ViewFrame {
|
||||
while (($nodeName = $this->process()) !== null) {
|
||||
public function isPlaying() : bool{
|
||||
return $this->playing;
|
||||
}
|
||||
|
||||
public function nextFrame(): ?ViewFrame {
|
||||
$actions = new ActionList();
|
||||
if(!$this->playing){
|
||||
return $this->lastFrame;
|
||||
}
|
||||
while (($nodeName = $this->process($actions)) !== null) {
|
||||
$this->next();
|
||||
|
||||
if ($nodeName === "ShowFrame") {
|
||||
|
@ -179,12 +215,26 @@ class SWFTreeProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
if ($nodeName === null) {
|
||||
return null;
|
||||
if ($nodeName === null) { //Loop again
|
||||
$this->frame = 0;
|
||||
$this->index = 0;
|
||||
$this->layout = new ViewLayout($this->layout->getObjectId(), null);
|
||||
return $this->lastFrame !== null ? $this->nextFrame() : null;
|
||||
}
|
||||
|
||||
++$this->frame;
|
||||
//TODO $this->layout->hasFrame();
|
||||
return $this->layout->nextFrame($actions);
|
||||
|
||||
$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;
|
||||
}
|
||||
}
|
|
@ -33,4 +33,8 @@ class ShapeDefinition implements ObjectDefinition {
|
|||
|
||||
return new ShapeDefinition($element["shapeId"], Rectangle::fromArray($element["shapeBounds"]), $drawPathList);
|
||||
}
|
||||
|
||||
public function getSafeObject() : ShapeDefinition{
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -4,20 +4,15 @@ namespace swf2ass;
|
|||
|
||||
class SpriteDefinition implements MultiFrameObjectDefinition {
|
||||
public int $id;
|
||||
/** @var ViewFrame[] */
|
||||
public array $frames;
|
||||
|
||||
public int $frameCounter;
|
||||
private SWFTreeProcessor $swf;
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param ViewFrame[] $frames
|
||||
* @param int $frameCounter
|
||||
*/
|
||||
public function __construct(int $id, array $frames, int $frameCounter = 0) {
|
||||
private ?ViewFrame $currentFrame = null;
|
||||
|
||||
|
||||
public function __construct(int $id, SWFTreeProcessor $swf) {
|
||||
$this->id = $id;
|
||||
$this->frames = $frames;
|
||||
$this->frameCounter = $frameCounter % count($this->frames);
|
||||
$this->swf = $swf;
|
||||
}
|
||||
|
||||
public function getObjectId(): int {
|
||||
|
@ -26,26 +21,19 @@ class SpriteDefinition implements MultiFrameObjectDefinition {
|
|||
|
||||
public function getShapeList(?float $ratio): DrawPathList {
|
||||
$list = new DrawPathList();
|
||||
foreach ($this->frames[$this->frameCounter]->render(0, [], null, null)->getObjects() as $object) {
|
||||
$list = $list->merge($object->drawPathList);
|
||||
if($this->currentFrame !== null){
|
||||
foreach ($this->currentFrame->render(0, [], null, null)->getObjects() as $object) {
|
||||
$list = $list->merge($object->drawPathList);
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function getFrameCounter(): int {
|
||||
return $this->frameCounter;
|
||||
}
|
||||
|
||||
public function getFrame(int $frameNumber): ?ViewFrame {
|
||||
return $this->frames[$frameNumber] ?? null;
|
||||
}
|
||||
|
||||
public function nextFrame(): ViewFrame {
|
||||
$f = $this->frames[$this->frameCounter];
|
||||
++$this->frameCounter;
|
||||
if ($this->frameCounter >= count($this->frames)) {
|
||||
$this->frameCounter = 0;
|
||||
}
|
||||
return $f;
|
||||
return $this->currentFrame = $this->swf->nextFrame();
|
||||
}
|
||||
|
||||
public function getSafeObject() : SpriteDefinition{
|
||||
return new SpriteDefinition($this->id, new SWFTreeProcessor($this->id, $this->swf->getTags(), $this->swf->getObjectCollection()));
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
namespace swf2ass;
|
||||
|
||||
|
||||
use swf2ass\actions\ActionList;
|
||||
|
||||
class ViewLayout {
|
||||
private ?ViewLayout $parent;
|
||||
|
||||
|
|
8
src/actions/Action.php
Normal file
8
src/actions/Action.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace swf2ass\actions;
|
||||
|
||||
|
||||
interface Action {
|
||||
|
||||
}
|
11
src/actions/ActionList.php
Normal file
11
src/actions/ActionList.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace swf2ass\actions;
|
||||
|
||||
|
||||
class ActionList {
|
||||
|
||||
/** @var Action[] */
|
||||
public array $actions = [];
|
||||
|
||||
}
|
17
src/actions/GoToFrameAction.php
Normal file
17
src/actions/GoToFrameAction.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace swf2ass\actions;
|
||||
|
||||
|
||||
class GoToFrameAction implements Action {
|
||||
private int $frame;
|
||||
|
||||
public function __construct(int $frame){
|
||||
$this->frame = $frame;
|
||||
}
|
||||
|
||||
public function getFrame() : int{
|
||||
return $this->frame;
|
||||
}
|
||||
|
||||
}
|
17
src/actions/GoToLabelAction.php
Normal file
17
src/actions/GoToLabelAction.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace swf2ass\actions;
|
||||
|
||||
|
||||
class GoToLabelAction implements Action {
|
||||
private string $label;
|
||||
|
||||
public function __construct(string $label){
|
||||
$this->label = $label;
|
||||
}
|
||||
|
||||
public function getLabel() : string{
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
}
|
7
src/actions/NextFrameAction.php
Normal file
7
src/actions/NextFrameAction.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace swf2ass\actions;
|
||||
|
||||
|
||||
class NextFrameAction implements Action {
|
||||
}
|
9
src/actions/PlayAction.php
Normal file
9
src/actions/PlayAction.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace swf2ass\actions;
|
||||
|
||||
|
||||
class PlayAction implements Action {
|
||||
|
||||
|
||||
}
|
7
src/actions/PreviousFrameAction.php
Normal file
7
src/actions/PreviousFrameAction.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace swf2ass\actions;
|
||||
|
||||
|
||||
class PreviousFrameAction implements Action {
|
||||
}
|
17
src/actions/SetTargetAction.php
Normal file
17
src/actions/SetTargetAction.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace swf2ass\actions;
|
||||
|
||||
|
||||
class SetTargetAction implements Action {
|
||||
private string $target;
|
||||
|
||||
public function __construct(string $target){
|
||||
$this->target = $target;
|
||||
}
|
||||
|
||||
public function getTarget() : string{
|
||||
return $this->target;
|
||||
}
|
||||
|
||||
}
|
9
src/actions/StopAction.php
Normal file
9
src/actions/StopAction.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace swf2ass\actions;
|
||||
|
||||
|
||||
class StopAction implements Action {
|
||||
|
||||
|
||||
}
|
23
src/actions/WaitForFrameAction.php
Normal file
23
src/actions/WaitForFrameAction.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace swf2ass\actions;
|
||||
|
||||
|
||||
class WaitForFrameAction implements Action {
|
||||
private int $frame;
|
||||
private int $skipCount;
|
||||
|
||||
public function __construct(int $frame, int $skipCount){
|
||||
$this->frame = $frame;
|
||||
$this->skipCount = $skipCount;
|
||||
}
|
||||
|
||||
public function getFrame() : int{
|
||||
return $this->frame;
|
||||
}
|
||||
|
||||
public function getSkipCount() : int{
|
||||
return $this->skipCount;
|
||||
}
|
||||
|
||||
}
|
|
@ -125,6 +125,10 @@ if ($swf->header["signature"]) {
|
|||
$keyFrameInterval = 10 * $processor->getFrameRate(); //kf every 10 seconds TODO: make this dynamic, per-shape
|
||||
$lastFrame = null;
|
||||
while(($frame = $processor->nextFrameOutput()) !== null){
|
||||
$lastFrame = $frame;
|
||||
if(!$processor->isPlaying()){
|
||||
break;
|
||||
}
|
||||
$audio = $processor->getAudio();
|
||||
if($audio !== null and $frameOffset === 0){
|
||||
if($audio->getStartFrame() === null){
|
||||
|
@ -132,7 +136,6 @@ if ($swf->header["signature"]) {
|
|||
}
|
||||
$frameOffset = $audio->getStartFrame();
|
||||
}
|
||||
$lastFrame = $frame;
|
||||
|
||||
$frame->setFrameOffset($frameOffset);
|
||||
|
||||
|
|
Loading…
Reference in a new issue