ラベル Flash Lite の投稿を表示しています。 すべての投稿を表示
ラベル Flash Lite の投稿を表示しています。 すべての投稿を表示

2009年9月3日木曜日

Flash Lite 1.1 で関数

言語で関数を定義することはできないけれど
通常は再生されないフレームにアクションを書いて
call(フレーム名) とする方法が使われる。

しかし、これは関数と言うよりはサブルーチンだ。
普通は再帰呼び出しすることはできない。

「それじゃ、引数や返り値の受け渡しのためにスタックを実装すれば、関数になるのでは?」

と思って作ってみた。

いろいろな実装方法が考えられるけれど、とりあえず次のようなルールとする。
  • 関数への引数は、関数を呼び出す側でスタックに積む。
  • 関数はスタックを参照して引数を得る。
  • 関数は返り値をスタックに積む。
  • 関数呼び出しの後に引数と返り値をスタックから取り除くのは、関数を呼び出す側の責任。

ルートムービークリップのフレーム1のアクション
sp = -1; // スタックポインタの初期化

// 引数をスタックに積む
++sp;
eval( "s" add sp ) = 12;

call ( "fact" ); // 関数呼び出し

// 答えをスタックから取り除く
r = eval ( "s" add sp );
--sp;

trace ( r ); // 確認

stop();

ルートムービークリップのフレーム2のアクション
// 階乗を計算する関数
n = eval ( "s" add sp );
if ( n == 0 ) {
eval ( "s" add sp ) = 1; // 引数をスタックから取り除き、答えをスタックに積む。つまりspは変化しない。
} else {
// 引数をスタックに積む
++sp;
eval ( "s" add sp ) = n - 1;
call ( "fact" );
r = eval ( "s" add sp ); // 関数の答えを取得する。
--sp; // スタックポインタを戻す
n = eval ( "s" add sp ); // n は再帰呼び出しで変化してるので復帰させる。
eval ( "s" add sp ) = r * n; // 引数をスタックから取り除き、答えをスタックに積む。つまりspは変化しない。
}

最後にルートムービークリップのフレーム2に名前"fact"をつけてプレビュー。

479001600

12!(12の階乗)を計算できた。
関数できた。
・・・かなり面倒だな。

Flash Lite 1.1でカレンダー計算:前の日を求める

prevday.as
// 前の日の日付を計算する
//
// @param a0 ... 西暦年 (例: 2009 )
// @param a1 ... 月 (1?12)
// @param a2 ... 日 (1?31)
//
// @return a0 ... 西暦年 (例: 2009 )
// @return a1 ... 月 (1?12)
// @return a2 ... 日 (1?31)
//
--a2;
if (0 >= a2) {
switch (a1) {
case 1:
a0 -= 1; a1 = 12; a2 = 31;
break;
case 2:
case 4:
case 6:
case 8:
case 9:
case 11:
--a1; a2 = 31;
break;
case 3:
a1 = 2;
if ((a0 % 4 == 0 && a0 % 100 != 0) || (a0 % 400 == 0)) { // 閏年
a2 = 29;
} else {
a2 = 28;
}
break;
case 5:
case 7:
case 10:
case 12:
--a1; a2 = 30;
break;
}
}

Flash Lite 1.1でカレンダー計算:次の日を求める

nextday.as
// 次の日の日付を計算する
//
// @param a0 ... 西暦年 (例: 2009 )
// @param a1 ... 月 (1?12)
// @param a2 ... 日 (1?31)
//
// @return a0 ... 西暦年 (例: 2009 )
// @return a1 ... 月 (1?12)
// @return a2 ... 日 (1?31)
//
++a2;
switch (a1) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
if (31 < a2) { ++a1; a2 = 1; }
break;
case 2:
if ((a0 % 4 == 0 && a0 % 100 != 0) || (a0 % 400 == 0)) { // 閏年
if (29 < a2) { ++a1; a2 = 1; }
} else {
if (28 < a2) { ++a1; a2 = 1; }
}
break;
case 4:
case 6:
case 9:
case 11:
if (30 < a2) { ++a1; a2 = 1; }
break;
case 12:
if (31 < a2) { ++a0; a1 = 1; a2 = 1; }
break;
}

Flash Lite 1.1でカレンダー計算:曜日を求める

weekday.as
// 日付から曜日を求める
//
// @param a0 ... 西暦年 (例: 2009)
// @param a1 ... 月 (1?12)
// @param a2 ... 日 (1?31)
//
// @return r0 ... 0?6 {0:日曜, 1:月曜, ... , 6:土曜}
//
if (2 >= a1) { // 1月と2月は前年の13月と14月と見なす
--a0;
a1 += 12;
}
// Zellerの公式の変形式
r0 = (a0+int(a0/4)-int(a0/100)+int(a0/400)+int((13*a1+8)/5)+a2)%7;
if (12 < a1) { // 13月と14月を元に戻す
++a0;
a1 -= 12;
}

SWF4でevalする時のTips

Flash CS4で作成したSWF4のバイトコードを読んでみた。
SWF4はFlash Lite 1.1で作成したプロジェクトの出力フォーマット。

ActionScriptで
eval(varInstName).varname = "value";
このコードは、次のようなバイトコードになる。
1: ActionPush "varInstName"
2: ActionGetVariable
3: ActionPush ":"
4: ActionStringAdd
5: ActionPush "varname"
6: ActionStringAdd
7: ActionPush "value"
8: ActionSetVariable
一方、
eval(varInstName add ":varname") = "value";
同じ効果を持つこのコードは、
1: ActionPush "varInstName"
2: ActionGetVariable
3: ActionPush ":varname"
4: ActionStringAdd
5: ActionPush "value"
6: ActionSetVariable
にコンパイルされるので、":"と"varname"をActionStringAddするコードを1つにできて、swfのバイトコードを6バイト減量できる。
命令数も減るので運がよければ速くなるかも。

ちなみに、
eval("/InstName:varname") = "value";
_root.InstName.varname = "value";
は、同じバイトコードを出力し、
1: ActionPush "/InstName:varname"
2: ActionPush "value"
3: ActionSetVariable
だった。

2009年7月29日水曜日

Flash Lite 1.1 のルートムービークリップの変数を動的生成してみた

swfの動的生成はswfmillmingという方法があるけれど、ひな形となるswfの変数だけを動的に変えるだけでよい場合にはswfバイナリを直接変更するという方法もあるという例。

生成した変数はルートムービークリップの変数になるようだ。変数名と同じ変数名でダイナミックTextインスタンスをステージに配置すれば、動的設定した文字列を表示することもできる。

ちなみに、検証にはFlash Lite 1.1で作成したswfを使った。

swf.rb
#!/usr/bin/env ruby
# -*- encoding: utf-8 -*-

require 'stringio'

module SWF
def self.read(src)
header = src.read(9)
x = (header[8] >> 3) * 4 + 5
header_size = ((((8 - (x & 7)) & 7) + x) / 8) + 12 + 5
header << src.read(header_size - 9)
body = src.read
[header, body]
end

class Vars
HD = "\x3f\x03\x00\x00\x00\x00"
BE = "\x96"
ZE = "\x00"
ZB = ZE + BE
ED = "\x00\x1d"

def initialize
@vars = []
end

def add(key, value)
@vars << [key, value]
end

def to_bytes
bytes = StringIO.new
bytes << HD
@vars.each do |key, val|
bytes << BE << [key.size + 2].pack('v') << ZE << key
bytes << ZB << [val.size + 2].pack('v') << ZE << val << ED
end
bytes << ZE
bytes.seek 0
bytes = bytes.read
bytes[2, 4] = [bytes.size - 6].pack('V')
bytes
end

def apply(src_io, dst_io)
vars = to_bytes
header, body = SWF.read(src_io)
header[4, 4] = [header.size + body.size + vars.size].pack('V')
dst_io << header
dst_io << vars
dst_io << body
end
end
end

if __FILE__ == $0
require 'yaml'
require 'optparse'
dat, src, dst = nil
OptionParser.new do |opt|
opt.on('-v VARS.yaml'){|v| dat = v }
opt.on('-i INPUT.swf'){|v| src = v }
opt.on('-o OUTPUT.swf'){|v| dst = v }
opt.parse!(ARGV)
unless dat && src && dst
opt.parse!(["-help"])
end
end
vars = SWF::Vars.new
YAML.load_file(dat).each{|key, value| vars.add(key, value) }
File.open(src, 'rb') do |s|
File.open(dst, 'wb') do |d|
vars.apply(s, d)
end
end
end

2009年6月23日火曜日

CentOS 5.2 で swfmill をソースからビルド

pkg-configが使えなくてちょっと苦しんだ。

libxml2-2.7.3.tar.gz を ./configure ; make ; make install
libxslt-1.1.25.tar.gz を ./configure ; make ; make install
freetype-2.3.9.tar.bz2 を ./configure ; make ; make install
libpng-1.2.37.tar.bz2 を ./configure ; make ; make install

最後に、swfmill-0.2.12.tar.gz を

patch -p 1 <>
export XML_CFLAGS=-I/usr/local/include/libxml2
export XML_LIBS="-L/usr/local/lib -lxml2"
export XSLT_CFLAGS=-I/usr/local/include/libxslt
export XSLT_LIBS="-L/usr/local/lib -lxslt -lexslt"
export FREETYPE_CFLAGS=-I/usr/local/include/freetype2
export FREETYPE_LIBS="-L/usr/local/lib -lfreetype"
export PNG_CFLAGS=-I/usr/local/include/libpng12
export PNG_LIBS="-L/usr/local/lib -lpng"
./configure
make

swfmill.cpp:395: error: ‘xslt_simple’ was not declared in this scope
こんなこと言われたので、vi +395 src/swfmill.cpp して、適当な位置に extern const char* xslt_simple; 追加。

make
su
make install
ldconfig

2009年6月16日火曜日

FlashコンテンツからFlash Lite 1.1コンテンツへの変換

最近の贅沢な高級言語からFlash Lite 1.1初心者になるといろいろ足りなくて困る。
後で読もう。
FlashコンテンツからFlash Lite 1.1コンテンツへの変換

Flash Lite 1.1 でカウントダウンしてみた

CountDown
//////////////////////////////////////////////////////////////////////
// 現在日時からXデーまでのカウントダウン
//
// 結果は4つの変数に算出する。「あと{dT}日と{HT}時間{MT}分{ST}秒」
//dT = 0; // 残り日数
//HT = 0; // 時間
//MT = 0; // 分
//ST = 0; // 秒
//////////////////////////////////////////////////////////////////////
// Xデー
yL = 2009;
mmL = 7;
dL = 7;
HL = 0;
ML = 0;
SL = 0;
//////////////////////////////////////////////////////////////////////
// 現在日時取得
yR =fscommand2("GetDateYear");
mmR = fscommand2("GetDateMonth");
dR = fscommand2("GetDateDay");
HR = fscommand2("GetTimeHours");
MR = fscommand2("GetTimeMinutes");
SR = fscommand2("GetTimeSeconds");
if(!yR){
debug_ = '現在時刻を取得できなかったYo';
stop();
}
//////////////////////////////////////////////////////////////////////
// Xデーを表示する。「年」を表示
yyyy_ = yL;
//////////////////////////////////////////////////////////////////////
// Xデーを表示する。「月」を2桁で表示
if(10 > mmL){
mo_ = '0' add mmL;
}
else{
mo_ = String(mmL);
}
//////////////////////////////////////////////////////////////////////
// Xデーを表示する。「日」を2桁で表示
if(10 > dL){
dd_ = '0' add dL;
}else{
dd_ = String(dL);
}
//////////////////////////////////////////////////////////////////////
// Xデーを表示する。「時」を2桁で表示
if(10 > HL){
hh_ = '0' add HL;
}else{
hh_ = String(HL);
}
//////////////////////////////////////////////////////////////////////
// Xデーを表示する。「分」を2桁で表示
if(10 > ML){
mi_ = '0' add ML;
}else{
mi_ = ML;
}
//////////////////////////////////////////////////////////////////////
// Xデーを表示する。「秒」を2桁で表示
if(10 > SL){
ss_ = '0' add SL;
}else{
ss_ = SL;
}
//////////////////////////////////////////////////////////////////////
// Xデーを2000年1月1日からの経過秒数に変換する。dtLが結果。
dtL = 0;
for(i = 2000; i < yL; ++i){
if((i % 4 == 0) ? ((i % 100 == 0) ? (i % 400 == 0) : true) : false){
dtL += 366;
} else {
dtL += 365;
}
}
switch(mmL){
case 2: dtL += 31; break;
case 3: dtL += 59; break;
case 4: dtL += 90; break;
case 5: dtL += 120; break;
case 6: dtL += 151; break;
case 7: dtL += 181; break;
case 8: dtL += 212; break;
case 9: dtL += 243; break;
case 10: dtL += 273; break;
case 11: dtL += 304; break;
case 12: dtL += 334; break;
}
if(2 < mmL && ((yL % 4 == 0) ? ((yL % 100 == 0) ? (yL % 400 == 0) : true) : false)){
dtL += 1;
}
dtL += dL;
dtL = (dtL * 24 * 60 * 60) + (HL * 60 * 60) + (ML * 60) + SL;
//////////////////////////////////////////////////////////////////////
// 現在日時を2000年1月1日からの経過秒数に変換する。dtRが結果。
dtR = 0;
for(i = 2000; i < yR; ++i){
if((i % 4 == 0) ? ((i % 100 == 0) ? (i % 400 == 0) : true) : false){
dtR += 366;
} else {
dtR += 365;
}
}
switch(mmR){
case 2: dtR += 31; break;
case 3: dtR += 59; break;
case 4: dtR += 90; break;
case 5: dtR += 120; break;
case 6: dtR += 151; break;
case 7: dtR += 181; break;
case 8: dtR += 212; break;
case 9: dtR += 243; break;
case 10: dtR += 273; break;
case 11: dtR += 304; break;
case 12: dtR += 334; break;
}
if(2 < mmR && ((yR % 4 == 0) ? ((yR % 100 == 0) ? (yR % 400 == 0) : true) : false)){
dtR += 1;
}
dtR += dR;
dtR = (dtR * 24 * 60 * 60) + (HR * 60 * 60) + (MR * 60) + SR;
//////////////////////////////////////////////////////////////////////
// Xデーと現在日時の差を計算して、{dT}日{HT}時間{MT}分{ST}秒にする。
if(dtL < dtR){
debug_ = 'もう過ぎてるYo';
stop();
}
dtT = dtL - dtR;
dT = int(dtT / (24 * 60 * 60));
HT = int((dtT / (60 * 60)) % 24);
MT = int((dtT / 60) % 60);
ST = int(dtT % 60);
//////////////////////////////////////////////////////////////////////
// Xデーまでの「日数」を4桁で表示
if(10 > dT){
dT_ = '000' add dT;
}
else if(100 > dT){
dT_ = '00' add dT;
}
else if(1000 > dT){
dT_ = '0' add dT;
}
else{
dT_ = String(dT);
}
//////////////////////////////////////////////////////////////////////
// Xデーまでの「時間」を2桁で表示
if(10 > HT){
HT_ = '0' add HT;
}
else{
HT_ = String(HT);
}
//////////////////////////////////////////////////////////////////////
// Xデーまでの「分」を2桁で表示
if(10 > MT){
MT_ = '0' add MT;
}
else{
MT_ = String(MT);
}
//////////////////////////////////////////////////////////////////////
// Xデーまでの「秒」を2桁で表示
if(10 > ST){
ST_ = '0' add ST;
}
else{
ST_ = String(ST);
}
//////////////////////////////////////////////////////////////////////