Away3DのWhiteShadingBitmapMaterialでメモリリーク

Away3DのWhiteShadingBitmapMaterialを普通に使ってるとBitmapDataをガンガンキャッシュしてメモリリーク起こすのでclearCache()してね、とのこと。

Issue 95 – away3d – Feature to clear bitmap cache in WhiteShadingBitmapMaterial (or texture setter) – Realtime 3D engine for Flash – Google Project Hosting

取り急ぎ5秒おきにキャッシュクリアして回避。

package wimax.away3d.material 
{
    import away3d.materials.WhiteShadingBitmapMaterial;
    import flash.display.BitmapData;
    import flash.events.TimerEvent;
    import flash.utils.Timer;
    
    public class ImprovedWhiteShadingBitmapMaterial extends WhiteShadingBitmapMaterial 
    {
        public var clearCacheInterval:int = 5000;
        
        public function ImprovedWhiteShadingBitmapMaterial(bitmap:BitmapData, init:Object=null) 
        {
            super(bitmap, init);
            
            var t:Timer = new Timer(clearCacheInterval);
            t.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void
            {
                clearCache();
            });
            t.start();
        }
    }
}

iOSで行間調整、カーニングするメモ

UILabelの行間、カーニング調整できないクソ仕様に悶絶したので代替手段としてCoreTextを調べてみたメモ。

・もろもろパラメータ設定したNSAttributedStringを用意する。指定できるパラメータはCoreText.framework内CTStringAttributes.hを参照。

・CTFramesetterCreateWithAttributedString(CFAttributedString*)でCTFramesetterRef取得する。

・CoreFoundationとObjective-Cのデータ型はだいたい互換性があるらしく、引数がCF~のとこに、同名のNS~を(CF~)NS~みたいにキャストしてつっこめれる。

・CGPathCreateMutable()でCGMutablePathRef取得する。

・CGPathAddRect(CGMutablePathRef, NULL, self.bounds)で描画範囲を設定。

・取得したCTFramesetterRefとCGMutablePathRefからCTFramesetterCreateFrame(CTFramesetterRef, CFRange, CGPathRef, NULL)を使ってCTFrameRefを作る。

・UIViewのdrawRect:(CGRect)rect内でUIGraphicsGetCurrentContext()使ってCGContextRef取得。

・CTFrameDraw(CTFrameRef, CGContextRef)でテキスト描画。

・UIViewとCoreGraphicsで座標系が違うので、
CGContextTranslateCTM(CGContextRef, 0, self.bounds.size.height);
CGContextScaleCTM(CGContextRef, 1, -1);
で上下反転させておく。

CoreFoundationとかガチのC言語な上、手続きがめんどすぎるのでよっぽどのことがない限りUIWebViewで描画した方がよい。
あとCoreTextの日本語資料少な過ぎで死ぬ。

参考:
Core Text Programming Guide: Introduction
Text Layout With Core Text
CoreText.framework – iPhone Development Wiki

動的に生成されるURLに対して固有のOGPを生成する方法メモ

http://hoge.com/#1000 みたいな、ハッシュ以下の値に対してコンテンツを書き換えるサイトで、それぞれのハッシュに応じて異なるOpen Graph Protocol(OGP)を吐き出したい時の対処法。

フェイスブック、ミクシィ、グリーで使われている OGP (Open Graph Protocol) とは何か
http://d.hatena.ne.jp/amachang/20110117/1295233078

1. まず同一ドメイン内に、OGP吐き出し用のPHPを用意する。

ex) http://hoge.com/share.php

2. 元のhtmlと同一のハッシュを受け取ってその値に応じたOGPを吐くようにする。

ex) http://hoge.com/share.php?id=1000

3. html内に設置したShareボタン、Likeボタンの対象URLを上記のshare.phpにする。

 <div data-href="http://hoge.com/share.php?id=1000" data-send=false data-layout="button_count" data-width=450 data-show-faces=false></div>

4. このままだとウォールにshare.phpのURLが投稿されてしまい、ウォールからアクセスしたユーザーがshare.phpに飛んでしまうので、share.php内でfacebookのクローラー以外を元のhtmlにリダイレクトする。
facebookのクローラーはUserAgant内の“facebookexternalhit”の有無で判定する。

Best Practices – Facebook開発者
http://developers.facebook.com/docs/best-practices/

5. 以下share.phpの概要

<?php
$id = $_GET["id"];
$ua = $_SERVER['HTTP_USER_AGENT'];
 
//facebook crowlerじゃなかったらリダイレクト
if (!preg_match('/facebookexternalhit/i', $ua))
{
    header("HTTP/1.1 301 Moved Permanently");
    header("Location: http://hoge.com/#" . $id);
    exit;
}
 
//idに応じて情報を取得する
$api = "http://hoge.com/api?id=" . $id;
$json = file_get_contents($api);
$user_data = json_decode($json);
$username = htmlspecialchars($user_data->result->username);
$img_path = htmlspecialchars($user_data->result->img_path);
 
?><!DOCTYPE html> 
<html lang="en" xmlns:og="http://ogp.me/ns#"> 
    <head>
        <meta charset="utf-8"> 
        <meta property="og:title" content="<?=$username?>'s page">
        <meta property="og:description" content="SITE DESCRIPTION">
        <meta property="og:url" content="http://hoge.com/#<?=$id?>">
        <meta property="og:image" content="<?=$img_path?>">
        <link rel="image_src" href="<?=$img_path?>">
        <title><?=$username?>'s page</title>
    </head>
    <body>
        <script type="text/javascript">location.replace("http://hoge.com/#<?=$id?>");</script>
    </body>
</html>

ActionScript 3 SDK for Facebook Platform API ハマリどころメモ

ActionScript 3 SDK for Facebook Platform APIを使う時に、attributes.nameを指定せずattributes.idだけを指定してswfobject.embedSWFすると、SDK内のExternalInterface.objectIDを参照している箇所でnullが返ってjsの方でエラーが出るブラウザがある。

このままだとjsの処理が止まってFB.loginとかFB.apiでコールバックが呼ばれなくなってしまうので、attributes.idと同じ名前をattributes.nameで指定してExternalInterface.objectIDを参照できるようにする。

var flashvars = {
};
 
var params = {
    base:'.',
    menu:'false',
    wmode: 'window',
    allowFullScreen:'true',
    allowscriptaccess:'always'
};
 
var attributes = {
    id:"hoge", //←これと
    name:"hoge" //←これを指定する
};
 
swfobject.embedSWF('main.swf', 'flashcontent', '100%', '100%', '10.0.0', '', flashvars, params, attributes);

Objective-C を強引に AS3 で例えるメモ

全部雰囲気で理解してるので間違ってる可能性大です。

変数宣言

プリミティブ型
int num → var num:int

クラス型
MyClass *myClass → var myClass:MyClass

※プリミティブ型以外の型は変数宣言で*付ける

ディスプレイオブジェクト的な概念

UIView → DisplayObject
UIResponder → InteractiveObject
addSubView → addChild
CGContextRef → Graphics
UIImage → BitmapData
UIImageView → Bitmap

座標指定
view.center = CGPointMake(100, 200)

view.x = 100;
view.y = 200;

リサイズ
view.size = CGSizeMake(100, 200)

view.width = 100;
view.height = 200;

メソッド

[instance method] → instance.method()
method:は:までがメソッド名

イベントハンドラ

[obj addTarget:self action:@selector(nullEventHandler:) forControlEvents:NullEventNull]

obj.addEventListener(NullEvent.NULL, nullEventHandler)

ヌル

nil → null

タイマー

NSTimer → Timer

文字列

@”This is text” → “This is text”

関数の定義

– (void)func: (NSString)arg1 argument2:(NSString)arg2 argument3:(NSString)arg3
{
}
※argument2とargument3は引数名(ラベル)で省略可。

private function func(arg1:String, arg2:String, arg3:String):void
{
}

関数の呼び出し

[obj func:@”引数1″ argument2:@”引数2″ argument3:@”引数3″];

obj.func(“引数1″, “引数2″, “引数3″);

コンストラクタ呼び出し

[[Class alloc] init] → new Class()

用語

プロトコル → インターフェイス

デリゲート

//インターフェイス(プロトコル)で通知用の関数定義
interface IHoge
{
function onHoge():void;
}

//デリゲートされるクラス
class Hoge implements IHoge
{
public function onHoge():void
{
trace(“called Hoge”);
}
}

/*
イベント(この場合は初期化)が起こったらインターフェイス(プロトコル)に対して通知関数を呼ぶ

デリゲート?
*/
class Main()
{
public Main(hoge:IHoge)
{
hoge.onHoge();
}
}

実行順序

アプリ起動

main()実行

UIApplicationMain()実行

アプリケーションデリゲートオブジェクトを呼び出し
– アプリケーションデリゲートオブジェクト = UIApplicationDelegateプロトコルを採用(継承)したオブジェクト
– didFinishLaunchingWithOptions:

イベントループ
– ユーザーの操作等々
– アプリケーションデリゲートオブジェクト経由で各メソッドを呼び出す

アプリ終了準備 → applicationWillResignActive:

アプリ終了 → applicationDidEnterBackground:

参照:
http://developer.apple.com/jp/devcenter/ios/library/documentation/iPhoneAppProgrammingGuide.pdf

FlashからOAuth用のポップアップ開くメモ

ポップアップしたウインドウ(子)とFlashがのっかってる元のウインドウ(親)はLocalConnection経由でやりとりする。

流れとしては、

元FlashでOAuthするボタンを押す
 ↓
子ウインドウがポップアップする
 ↓
TwitterのOAuthページが表示される。
 ↓
OAuth完了する
 ↓
元Flashに完了した旨が通知される。
 ↓
ポップアップウインドウが閉じる
 ↓
Twitterに各種情報をとりに行く

という感じ。

ここで問題になるのがLocalConnectionをする時に同じConnect IDを使い回すと、同じページを開いた場合にconnect対象が複数になってしまい接続が失敗する。

これを回避するためにconnect用のIDにタイムスタンプを使う。

var connectID:String = String((new Date()).getTime());

Flashから子ウインドウを開く時に、

ExternalInterface.call('window.open("' + url + '", "' + connectID + '")');

もしくは、

navigateToURL(new URLRequest(url) , connectID);

のようにwindow.nameとして生成したIDを子ウインドウに渡す。

子ウインドウはtwitterのOAuth画面が開き、
リダイレクトでもどってきたページでwindow.nameを参照し、
flashvars経由でsend用のswf(通知側)にこのIDを渡す。
send用のswfはこのIDを使ってsendしOAuthが終了したことを親ウインドウに知らせる。

connectが完了したら子ウインドウは自分でwindow.closeして閉じる。

さらに問題になるのがブラウザごとのポップアップブロックの条件。
IEはnavigateToURLがブロックされ、
MacのSafariはポップアップしたページに

タグがあるとwindow.closeできなくなるので、
ExternalInterfaceからwindow.openを呼びウインドウを開く。

ExternalInterface.call('window.open("' + url + '", "' + connectID + '")');

それ以外のブラウザはnavigateToURLで開く。

さらにさらに、Firefox4でwindow.nameを指定してウインドウを開くと、
window.closeした時に他のタブ(親ページ)も巻き込んで閉じてしまうので、
connectIDの頭に”_blank”をつけて開く。

var connectID:String = "_blank" + connectID;

こんな感じ。

Flash、wmode=gpuのバグ?

最近Flashのサイトを制作した際にハマったバグを共有しておきます。

バグの内容は、FireFox、ChromeでFlashサイトを開くと画面が点滅するというものです。
今の段階の結論を言うと、swfをエンベットする時にwmodeをgpu以外のものにするとこの現象は起こらなくなります。

この現象はブラウザ、OS、Flash Playerのバージョンが同じ環境でも異なる機種のMacでは起こらなかったりとハードウェアに依存する部分もあるようです。

検証では以下の環境で現象が確認できました。

黒く点滅し続ける

Mac 10.6.7
Firefox 3.6.17
FlashPlayer 10 debug

Mac 10.4.11
Firefox 3.6.17
FlashPlayer 10.2

画面が真っ白になる

Mac 10.6.7
Firefox 3.6.17
FlashPlayer 10.1

Mac 10.6.7
Firefox 3.5.17
FlashPlayer 10.1.102.64

読み込み時一瞬黒くなる

Windows7
Chrome 11
FlashPlayer 10.2.159.1 debug

Windows7
Chrome 11
FlashPlayer 10.3.181.14 debug

これらの現象が発生する共通する条件は以下の2点です。
・wmodeがgpu
・Flash Playerの設定内「ハードウェアアクセラレーションを有効化」にチェックが入っている
※この項目はデフォルトでチェックが入っています。

また、Flashのパブリッシュ設定内の「ハードウェアアクセラレーション」に関してはこの現象に関係ないようです。

より詳しい情報がわかれば教えて頂けると助かります。
よろしくお願いします。

Cinema 4D お勉強リソースメモ

CINEMA4D (シネマ フォーディー) ~概要:主な機能
http://bit.ly/pSXKlW

★★C4D★★
http://bit.ly/pRcYL4

Ustream.tv: ユーザー maxonjapan: CINEMA 4Dの基本操作, CINEMA 4Dの基本操作の紹介。. ハウツー
http://bit.ly/qDRMl7

【初心者向け】 Cinema 4Dであそぼう – その1 – ‐ ニコニコ動画(原宿)
http://bit.ly/naMaTJ

QuickstartC4DR12JP.pdf
http://bit.ly/qcxPkX

CINEMA 4Dトレーニングサイト
http://bit.ly/pPtnx3

村人とC4Dのトップページ: 村人とC4D
http://bit.ly/qKmNAx

Cinema 4DとAfter Effectsを連携させる | AEP Project
http://bit.ly/pFiAfX

以下英語ソース

Cinema4D | Cgtuts+
http://bit.ly/rrSWPj

80+ Excellent Cinema 4D Tutorials and Best Practices | Tutorials | instantShift
http://bit.ly/nve0y5

Cinema 4D Tutorials (english voiceovers only) on Vimeo
http://bit.ly/puJSrT

マルチブックマーキングやってみたメモ

5月の頭ぐらいから1ヶ月ちかく、平日の朝10時に前日までに気になったリンクを Twitter + Facebook に一括ポストする試みをやってる。目的はO型特有の「おもしろいものを他人に勧めたくなる欲」の発散と、閲覧履歴のデータベース化。このマルチブックマーキング(複数のサービスに同じブックマークを残す)をするにあたってちょっと手の込んだことをやってるのでメモっとく。

おっきな流れは「ネタ収集」→「投稿」→「参照」。
以下詳細。

ネタの収集

まず日常的にネットを見てるなかでとにかく気になったものをどんどん Instapaper にポストしていく。
iPhone だと Twitter for iPhoneReeder がデフォルトで Instapaper への投稿に対応してる。(Facebook 上のリンクを一発で Instapaper にポストするいい方法あったら教えて下さい)

ついでに iPhone が圏外の環境から Instapaper に投稿する Tips。最近の iOS は圏外の状態でメールを送信すると、電波が入ったタイミングで自動的にメールを送信してくれる。これを利用して圏外の時は Twitter for iPhone、Reeder から Instapaper 投稿用のメールアドレスにリンクを送る。これで電波の状況を気にせず Instapaper に投稿できる。

各サービスへの投稿

Twitter と Facebook に指定時刻に投稿するために HootsuiteSchedule Message 機能を使う。この Schedule Message は指定のサービスに、指定の時刻に投稿ができる。

さらに投稿を簡略化するために Chrome の拡張機能 HootSuite Hootlet を使う。これは Chrome で今開いているページを2クリックで Schedule Message に投稿できる拡張機能。これを使って指定時刻に指定の内容を投稿する。

リンクの参照

残念ながら今のところ Twitter、Facebook には過去のポストをすべて遡って検索することができない。そこで Pinboardauto-add 機能を使って Twitter 上のリンクを自動収集させる。これを設定しておくと、Twitter 上でリンクをポストするとアドレス、タイトル、リンクを含むツイート全文を Pinboard に保存してくれる。これでツイートを含む全文が検索で引っかかるようになる。(さらにツイートにハッシュタグを埋め込んどくと自動的に Pinbord 上で同名のタグ付けもしてくれるらしい。)

ちなみに今までの自分のリンクはここに蓄積されてる。

フロー

飯喰いながら iPhone でネット見る
ウンコしながら iPhone でネット見る
街歩きながら iPhone でネット見る
ジョギングしながら iPhone でネット見る
 ↓
各アプリからひたすら Instapaper にポスト
 ↓
家でコーヒー飲みながら Instapaper からその日の 選りすぐりのリンクを Hootsuite に投稿する
 ↓
次の日の朝10時に各サービスに一括ポストされる
 ↓
あのサイトどこだっけ?
 ↓
Pinboard で検索
 ↓
(゚д゚)ウマー

今までおもしろいリンクは Delicious に投稿するだけだったけど、これらのサービスを経由することで「おもしろいものを他人に勧めたくなる欲」の発散と、閲覧履歴のデータベース化が同時に達成できるようになった。1つの石で2羽の鳥を落とすっていうアレですよ。

そもそものきっかけは、佐々木俊尚さん( @sasakitoshinao )の『キュレーションの時代』を読んで始めたんだけど、佐々木さんほどの品質のいいリンクを投稿してないせいか、投稿のたびに Twitter のフォロワーが激減したり、すごい暇人扱いされるので割と涙目だったりする。そんな感じ。

FWAにてSite Of The Dayを受賞しました

Helvatica FaceFWAにてSite Of The Dayを受賞しました。

FWAは1日1個カッチョエエサイトを掲載する系のサイトの先駆けで、自分も学生時代は毎日見てました。そこに自分の卒制がSOTD(Site Of The Day)入りしたのはなんだか感慨深い。

あと今月号のWeb Designingのone’s viewにもHelvatica Faceが掲載されました。こちらも合せてよろしくお願いします。