【Cocos2d-x3.0 rc0】LabelTTFのアンチエイリアスを無理やり外す

before
labelttf_a

after
labelttf_b

Cocos2d-xのLabelTTFにはデフォルトでアンチエイリアスがかかっている。
これが問題になることはあまり無いのかもしれないが、今回ちょっとこれが困る事態になった。
BMPフォントを使う方法やシェーダを自作する方法など回避策はあるらしいけれど、
もう少し手軽になんとかならないかと考えた。



LabelTTFのソースを覗く

ソースを覗いてみるとLabelTTFの中にLabelクラスを持っていて、
Labelクラスのノードにテクスチャを追加する形になっていた。

LabelTTF.cpp 32行目
LabelTTF::LabelTTF()
{
    _renderLabel = Label::create();
    this->addChild(_renderLabel);
    this->setAnchorPoint(Point::ANCHOR_MIDDLE);

Labelクラス922行目、createSpriteWithFontDefinitionメソッド内
    _textSprite = Sprite::createWithTexture(texture);
    _textSprite->setAnchorPoint(Point::ANCHOR_BOTTOM_LEFT);
    this->setContentSize(_textSprite->getContentSize());
    texture->release();

    Node::addChild(_textSprite,0,Node::INVALID_TAG);
}

つまりLabelTTFからgetChildrenしてLabelを取り出して
Labelから更にSpriteを取り出して無理やりダウンキャストすれば・・・?

無理やりSpriteを取り出してsetAliasTexParametersしようとしたけれど

	auto labelTTF_renderLabel = _label->getChildren().at(0);
	if (auto a = dynamic_cast<Label*>(labelTTF_renderLabel)) {
		auto b = a->getChildren().at(0);
		if (auto c = dynamic_cast<Sprite*>(b)) {
			c->getTexture()->setAliasTexParameters();
		}
	}

Sprite自体は取り出せたものの、これは失敗。
どうやらLabelは内部で毎フレーム新しくテクスチャを作っているらしい。
パフォーマンス考えるならBMPフォントにしろってのはそういうことか・・・。

CCLabel.cpp 948行目
void Label::updateContent()
{
    auto utf16String = cc_utf8_to_utf16(_originalUTF8String.c_str());
    setCurrentString(utf16String);
    setOriginalString(utf16String);
    if (_textSprite)
    {
        Node::removeChild(_textSprite,true);
        _textSprite = nullptr;
    }

つまりLabelTTF生成時に一度だけキャストしてアンチエイリアスを切っても
すぐにそのテクスチャは破棄されてしまうので意味がない。

結局

createSpriteWithFontDefinitionメソッド内のテクスチャを生成している部分に
自前でsetAliasTexParametersを差し込むことで一応なんとかできる。

    texture->initWithString(_originalUTF8String.c_str(),_fontDefinition);
	texture->setAliasTexParameters();// これを追記

    _textSprite = Sprite::createWithTexture(texture);
    _textSprite->setAnchorPoint(Point::ANCHOR_BOTTOM_LEFT);
    this->setContentSize(_textSprite->getContentSize());
    texture->release();

    Node::addChild(_textSprite,0,Node::INVALID_TAG);
}

ライブラリのコードに手を加えるのは気が引けるが、
幸いCocos2dはプロジェクト単位でcocos2dが複製されるので
変更したことをきちんと記録しておけばなんとかなるかな・・・。

使わせて頂いたフォント
Little Limit – 美咲フォント(misaki_gothic.ttf)

Posted on 4月 13, 2014 at 14:26 by 伊崎 · Permalink · Leave a comment
In: Cocos2d-x

【C++】この定数式には、必要な型”int”ではなく型”Type”が指定されています

enum classが便利だと聞いて使い始めてみたものの、以下のような構文エラーが出た。

VisualStudio2013だと以下のメッセージ。

この定数式には、必要な型"int"ではなく型"Type"が指定されています

Ideoneだとこんなメッセージ。
error: could not convert ‘AAA’ from ‘main()::A’ to ‘int’

書いていたコードは以下。

enum class A : int {
	AAA,
	BBB,
	CCC,
};

int main() {
	// your code goes here 
	switch (0) {
		case A::AAA:
			break;
		case A::BBB:
			break;
		case A::CCC:
			break;
	}
 
	return 0;
}

エラーの内容はswitchにint型が指定されてるのに分岐ではA型が使われているよ!というもの。
普通にenum class Aではなくenum Aなら引っかからないので少し戸惑った。




解決するには単純にキャストすればいい。

enum class A : int {
	AAA,
	BBB,
	CCC,
};

int main() {
	// your code goes here
	switch (static_cast<A>(0)) {
		case A::AAA:
			break;
		case A::BBB:
			break;
		case A::CCC:
			break;
	}
 
	return 0;
}

参考にさせて頂いたサイト
http://stackoverflow.com/questions/9062082/switch-statements-with-strongly-typed-enumerations

Posted on 4月 11, 2014 at 11:34 by 伊崎 · Permalink · Leave a comment
In: C/C++

無料で学べる大学講座 Gacco がすごそう

ふと朝ごはんを食べながらテレビを見ていると、ニュースで紹介されていた。
登録することで大学の講義が無料で受けられるらしい。

http://gacco.org/

ひとまず利用規約とプライバシーボリシを読んで会員登録。
5月19日にはじまる「インターネット」の受講を予約した。
ニュースで見てすぐに会員しようとしたらレスポンスが悪かった。テレビの影響力すげー。

各講座大体1ヶ月くらいで最後にテストがあるっぽい。
利用規約とプライバシーポリシは基本的によくあるサイト登録と同じ。
普通に使っている分には問題なさそう。

特に気をつけないといけないと思ったのは15条(2014/04/10現在)

1.会員は、私的使用の範囲でのみ講座コンテンツを使用することができます。

2.会員は、当社および講座提供者から事前の書面による許諾を得ることなく、不特定多数に視聴・閲覧せしめるなどの私的使用の範囲を超えた利用、および営利目的の利用はできません。

3.会員は、講座コンテンツを譲渡、複製、貸与、公衆送信その他当社または講座提供者が認めていない利用を行う、または第三者に行わせることはできません。

Posted on 4月 10, 2014 at 08:04 by 伊崎 · Permalink · Leave a comment
In: 日常

【Cocos2d-x3.0rc】Cocos2d-xのメモリ管理が簡単なように見えてかなりシビア

RefのサブクラスをVectorに入れて管理するときの話。
オブジェクトをまとめておきたくて、次のようなコードを書いた。

class Child : public cocos2d::Ref {
public:
    bool init();
    CREATE_FUNC(Child);

    void print() {
        CCLOG("piyo");
    }
};

class Parent {
public:
    cocos2d::Vector<Child*> getChildren() {
        return _children;
    }

    void addChild(Child* child) {
        this->getChildren().pushBack(child);
    }
    
private:
    cocos2d::Vector<Child*> _children;
};

Refクラス、及びメモリや参照について詳しい方ならば、
コードをみた時点で「そりゃそうだろ」と気付くかもしれませんが、
これを実際に使うとChildの不正参照で吹っ飛びます。

ダメなとこ

実際にアウトなのはgetChildrenメソッド。影響が一番最初にでるのはaddChildメソッド。
参照カウントは次のようになる。ここでアンダーバープレフィクスの付いた変数はSceneのメンバ。

ダメなコード
Scene::init() {
    _child * Child::craete();
    _parent.addObject(_child);
}

Scene::update() {
    _child->print();
  // _人人人人人人_
  // > 不正参照 <
  //  ̄Y^Y^Y^Y^Y ̄
}
動き
Scene::init() {
    _child = Child::create(); // 生成しただけなので参照カウント1
    _parent.addObject(_child);
    ---- この時点でも参照カウント1
    ---- this->getChildren().pushBack(child); // 内部でretainされるので参照カウント2
    // ここで参照カウント1に戻る
}// フレームの最後にAutoReleasePoolに消される。

Scene::update() {
    _child->print(); // オブジェクト削除済みで不正参照
}

あれ!!!!VectorにpushBackすれば内部でretainされるから保持されるんじゃないの\(^o^)/

お前のVecotorはコピーだったのさ!ざんねんだったね!!!!

/(^o^)\

つまりこういうこと。

Scene::init() {
    _child = Child::create(); // 生成しただけなので参照カウント1
    _parent.addObject(_child);
    ---- この時点でも参照カウント1
    ---- this->getChildren().pushBack(child); // 内部でretainされるので参照カウント2

    ---- this->getChildren()で取得できるのは_childrenのコピーなので、
    ---- そのコピーに対してpushBackするものの、コピー自体は変数で受け取っていないので即削除。
    ---- コピーのデストラクタ内でclearが呼ばれてreleaseされる

    // ここで参照カウント1に戻る
}// フレームの最後にAutoReleasePoolに消される。

getChildrenメソッドを参照かポインタで返すようにすれば一応解決。
cocos2d::Vector<Child*>& getChildren()

とりあえずRefを継承してcocos2d::Vectorかcocos2d::Mapに突っ込んでおけばいいんでしょ、
と思っていた時期が僕にもありました。

なんでこんなことをわざわざ書いたのか

この残念なミス、必ず不正参照で落ちてくれるならすぐに原因も分かったかもしれない。
しかしメモリ関連のバグでよくある「不正参照しつつも、しばらくは正常に動く」という状態になる。

今回はそこそこ浅い部分で見つかったからよかったものの、
がっつりコーディングしたあとに発生したら発見が相当面倒なタイプのバグになりうる。

Posted on 4月 4, 2014 at 18:55 by 伊崎 · Permalink · Leave a comment
In: Cocos2d-x

安全なウェブサイト運営入門が面白かった

IPAの情報セキュリティツールに「安全なウェブサイト運営入門」というのがあったのでやってみた。
http://www.ipa.go.jp/security/vuln/7incidents/index.html

情報処理の勉強をしていると文字ばっかりで中々頭に入らない部分が多いけれど、
こんな感じでストーリーがあると分かりやすいし記憶に残りやすくていいよなぁ。

安全なウェブサイト運営入門

Posted on 4月 1, 2014 at 17:02 by 伊崎 · Permalink · Leave a comment
In: 情報処理

【メモ】個人情報流出事件の想定賠償額

2006年、4億8156万円/件

安全なウェブサイト運営入門:第一話より


Posted on 4月 1, 2014 at 02:02 by 伊崎 · Permalink · Leave a comment
In: メモ

自宅サーバー構築メモ(Debian squeeze)#24 Gitインストール

インストール

#apt-get install git

確認

#git --version

Posted on 3月 13, 2014 at 09:03 by 伊崎 · Permalink · Leave a comment
In: サーバー

Cocos2d-x @Pokotsun Labs – 201研究室

これまで色々調べたこととかこのブログにまとめていたけれど、
もう少し見やすく、分かりやすくまとめたいと考えてた。

単純に年なのか、元からそうだったのか、どうにも最近物覚えが悪くて
新しいことを勉強しようとしても中々覚えていられない。
そこでやったことをすぐに見られるように少しWikiを触ってみていた。



ある程度記述の仕方にも慣れてきて、ページ自体の概観もそれなりにまとまったので
内容は中途半端ですが公開していこうと思います。

Cocos2d-x @Pokotsun Labs – 201研究室

ちょっとしたことや思いつきは今まで通りブログに書くとして、
がっつり調べたいときはこんな感じでまとめていけたらと考えています。

これ機に独自ドメインも取得したので、
もう少し自信をもって色々と活動していけたらと思います。

したがって近いうちにこのブログもURLが変わるかもしれません。
大抵「なにいってんの?」くらいの本当にチラシの裏な内容しか書いていませんが・・・

Posted on 3月 8, 2014 at 17:44 by 伊崎 · Permalink · Leave a comment
In: 日常