Spica*

プログラミングの話。

27歳になりました

ついに、なんとなーく27歳になってしまいました。 思うところいろいろあるのでつらつらーっと書こうかなと思います。。

スキルのこと

会社ではいろんなことを経験させてもらいまして、おかげさまで現時点でJavaScript/Java/Objective-C/PHP/ShellScriptがそれなりに扱えるようになりました。JavaScript/ShellScriptは独学だけど、会社の時間もちょいちょい使わせてもらってます。(勝手に)

最近はすごいWeb周りの技術が進んで、知らない間に選択肢も増え、フロントエンジニアとしてはまだまだ勉強しないといけないことが多いなあと感じています。例えば、Electronを使えば既知のWebの技術でWindows/Linux/Macアプリも作れることでしょう。

しかし、他の面もかなり発達していて、Raspberry Piなどの功績によりIoTの敷居が下がったり、JVM言語の発達(Java8の登場やScalaの普及、さらにはKotlinのじわじわと広がってる感など)を見ていると、バックエンドもどんどん変わり続けている印象を受けます。 同じように、組み込みなど、もっと下層の技術・環境も発達していることでしょう。。

僕はまだ漠然としか見れていないですが、それらをそれぞれ繋げば、もっと楽しいことが待っているんじゃないかと思っています。浅く広く、ただ最低限「僕の書いたコードは将来誰かが見るコード」という意識を持って勉強出来たらなぁと思ってます。

クリエイティブなこと

今までにも思っていたんだけれど、多分僕は絵や作曲、演奏などの「クリエイティブ」な部分は向いてないように感じてますw

これは実際にある程度やってから感じてます。多分今までのように、やれば上達するとは思うのだけれど、思い通りにならない部分を恥ずかしさと感じているのが大きいです。ある意味今まで上達したのはそういうのの上塗りをしていたのかなと感じることもあったり。やっぱりそっちよりもプログラミングのように、あるべき形まで「設計」をする方が、肌に合ってるのかなと感じてます。

ただ、もちろん何でもそうだと思うんですけど、傾向としてプログラミングは設計なのであるだけで、重なるところもあって、例えば、プロダクトデザインやWebデザインなんかは「設計」と「クリエイティブ」の中間になるのかなと感じてます。こないだ話題になった、五輪デザインの話なんか、すごい設計寄りの解説でしたねー。

なので、外堀を埋める形で、これからもクリエイティブなことは挑戦できたらなぁと思ってます。

結婚

結婚してもう早二年が経とうとしてます。いろいろありましたが、今は落ち着いていて、ゆったりとした生活を送っています。(忙しくなるので今日までだけど…)

変わったことはいろいろあるんですが…逆に言うと特別これってことが無い…。色んな所に出かけて、色んなことをしました。その場で楽しむことに集中しすぎて、SNSに投稿するのちょっとめんどくさいみたいになるので、あまり写真とかも無いw

Twitterでは氏にまくってますがエンジョイしてるだけだからね!!勘違いしないでよね!!!!

さて、ご飯食べてきます。

libGDXで3Dのモデル表示してみた

f:id:esperia:20150906175305p:plain

MagicaVoxelについての記事 を見てちょっと楽しそうだったので同じ所までやってみました。 libGDXプロジェクトを作成し、MagicaVoxel の標準で用意されているモデルをを、画面上に表示するところまでしてみました。環境はMac

プロジェクト作成

下記設定で作りました。普通ですね。

f:id:esperia:20150906175630p:plain

チュートリアルに沿ってコードを記述

Loading models using libGDX | blog.xoppa.comの通りにコードを書きます。

このドキュメント自体は、libgdx Wiki -> 3D Graphics -> Quick Start -> Basic 3D using libGDX | blog.xoppa.com -> Next: から飛べます。公式…というより公認?のページみたいです。

書くときは、importするクラスには注意して下さい。別パッケージに同じクラス名があるので、間違えるとビルドできません。

package com.esperia09.samples.libgdx.magicavoxel;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
import com.badlogic.gdx.utils.Array;

public class MyGdxGame extends ApplicationAdapter {
    private static final String PATH_MODEL = "chr_knight.g3db";
    public PerspectiveCamera cam;
    public CameraInputController camController;
    public ModelBatch modelBatch;
    public AssetManager assets;
    public Array<ModelInstance> instances = new Array<ModelInstance>();
    public Environment environment;
    public boolean loading;

    @Override
    public void create() {
        modelBatch = new ModelBatch();
        environment = new Environment();
        environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
        environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));

        cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        cam.position.set(7f, 7f, 7f);
        cam.lookAt(0, 0, 0);
        cam.near = 1f;
        cam.far = 300f;
        cam.update();

        camController = new CameraInputController(cam);
        Gdx.input.setInputProcessor(camController);

        assets = new AssetManager();
        assets.load(PATH_MODEL, Model.class);

        loading = true;
    }

    private void doneLoading() {
        Gdx.app.log(getClass().getSimpleName(), "doneLoading");
        Model ship = assets.get(PATH_MODEL, Model.class);
        ModelInstance shipInstance = new ModelInstance(ship);
        shipInstance.transform.setToScaling(0.5f, 0.5f, 0.5f);
        instances.add(shipInstance);
        loading = false;
    }

    @Override
    public void render() {
        if (loading && assets.update()) {
            doneLoading();
        }
        camController.update();

        Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

        modelBatch.begin(cam);
        modelBatch.render(instances, environment);
        modelBatch.end();
    }

    @Override
    public void dispose() {
        modelBatch.dispose();
        instances.clear();
        assets.dispose();
    }
}

これだけで表示完了…かつ、

  • ドラッグで移動
  • ホイールで拡大率変更

できます。すごい…

Androidの場合は、二本指での拡大と、スワイプでの回転ができました。

f:id:esperia:20150907201031p:plain

chr_knight.g3dbファイルは、MagicaVoxelについての記事で説明されているように、MagicaVoxelからexportし、libgdx/fbx-convを使って*.obj -> *.g3dbへ変換するとOKです。ちょっとつまずいたこともありましたが、その内容に関しては先程の記事にコメントつけました。

感想

数字全然僕ダメで、行列すら習ってない系だったのでかなり躊躇してたんですが、 最初の敷居すごい低かったのが嬉しかったです。 いや、これで何か考えてるわけではないんですが…何かするきっかけはできたかなという感じです。

express-generatorをforkして、ECT使えるようにした

ECTっていうのは、テンプレートエンジンの一つです。

ECT - Fastest JavaScript template engine with CoffeeScript syntax

このECT、テンプレートの継承が便利で、かつjadeのような特殊文法さが少ないので学習コストが低いのが特徴です。文法はejsに似てますが、若干違います。 実行速度も速いらしく、しばらくexpressと連携して使ってみたいなと思いまして、簡単に使えるようにしてみました。

インストール

npm uninstall -g express-generator
npm install -g esperia/generator

後者のコマンドを入力すると、僕がforkしたリポジトリ(esperia/generator)の方からダウンロード・インストールを行なってくれるようになってます。 一応ejsの方を参考にテストを書きまして、passしました。

使い方

express --ectで、現在のカレントディレクトリにプロジェクトを作製できます。

$ express --ect

   create : .
   create : ./package.json
   create : ./app.js
   create : ./public
   create : ./public/javascripts
   create : ./public/images
   create : ./public/stylesheets
   create : ./public/stylesheets/style.css
   create : ./routes
   create : ./routes/index.js
   create : ./routes/users.js
   create : ./views
   create : ./views/index.ect
   create : ./views/layout.ect
   create : ./views/error.ect
   create : ./bin
   create : ./bin/www

   install dependencies:
     $ cd . && npm install

   run the app:
     $ DEBUG=gen:* npm start

デフォルトに戻す場合

npm uninstall -g express-generator
npm install -g express-generator

参考

上記記事の内容を、コマンドでgenerateできるようにした感じです。(layout.ectとかは参考にしてないので多分記述違うだろうなあ…)

ECT出てからわりと経つのに、express-generatorモジュールに反映されてないの、多分理由があるんだと思ってる…。 PR投げてもいいけど、コミット整理するのめんどい(´・ω・`)

追記

言い忘れてた…。僕が改造したrepoですが、ちょっと気に食わなかったところ改造してます…。

  • publicディレクトリ内のディレクトリ名変更
    • javascripts -> js
    • stylesheets -> css
    • images -> img
  • テンプレート内の、HTMLの属性を囲むシングルクォートを、ダブルクォートに変更

細かいことなんですけどね…。

(2015-08-11追記: 上記独自仕様やめました。compassとかにも影響が出ることがわかったので…)

Zenfone 2 (ZE551ML) フロントパネル交換しようとして失敗した

追記(2015-08-29):直してる人居た!!( ASUS Zenfone2 自分でディスプレイ交換 - かりぶろ )すげー!

チックショーーーーー!!!

電源ボタン長押しするとバイブ一瞬発生する機能付き高級文鎮が完成しました。慣れない修理はするもんやないですね。ほんまに。

何度も何度も開けては端子接続しなおしたりしたんですけどだめだった。一応こうやってブログに書いてますけど、手順とかメモってるわけじゃないです。

元の状態

スマホおとしちゃって、本当にバッキバキだったんですよね。 それでもしばらく使ってたんですが、もう非常に見えにくいので、文鎮になってもいいから修理をしてみようと思ったのです。

f:id:esperia:20150719014354j:plain

購入したもの

www.amazon.co.jp

端末はこっち。

www.expansys.jp

参考にしたもの

Zenfone 2って、ググっても修理した動画やブログ出ないんですよね…。あたらしすぎるのかしら。 なので、 Zenfone 5の修理を参考にやってました。

もちろん基盤の形などは違うものの、基本的な流れは同じで、LCD上部と下部にフラットケーブルが入ってるところも同じ。「こうすればいいのか」的な流れはすぐに見出すことができました。 ただ、どこか扱いが乱暴だったのか、よくわからないんですけど治らなかったです。。

一点気になったのは、修理前のフロントパネルについてたチップの型番。交換前は「ERH484E」だったんですけど、交換後のパネルが「ERH504E」って書いてあった。間違えてZE550ML買ったのかと思ってしまったけど、間違えてたらそもそもディスプレイはまらないよね…。きっと気にしすぎなんだろう…。

まあなんせうまく行かなかったです。総額5万円程度吹っ飛んだ気がしますよよよ。うう…

写真

f:id:esperia:20150717215533j:plain

Ubuntu ServerにMinecraft forge入れた

f:id:esperia:20150704211440p:plain

  • リンクコピーする。

f:id:esperia:20150704212004p:plain

http://files.minecraftforge.net/.../forge-1.8-11.14.3.1450-installer.jar みたいなURLになる。 (forgeの広告表示開かないの、多分Forge提供側に迷惑かかるので直リンクは避けてます。)

サーバにSSHで繋いで、コマンドライン操作でダウンロードとインストール、セットアップする。

# ダウンロード
mkdir server-forge
cd server-forge
curl -O http://files.minecraftforge.net/.../forge-1.8-11.14.3.1450-installer.jar

# インストール
java -jar forge-1.8-11.14.3.1450-installer.jar nogui --installServer

# 一旦起動し、各種設定ファイルを作る
java -Xmx2048M -Xms1024M -jar forge-1.8-11.14.3.1450-universal.jar

# >>> ここで Ctrl + c とかで一旦サーバ止める。
# eula.txtを開き、 eula=false -> eula=true にする
vim ./eula.txt

# もう一回起動
java -Xmx2048M -Xms1024M -jar forge-1.8-11.14.3.1450-universal.jar

# >>> ここで stop と入力し一度サーバ止める
# server.propertiesが書かれているので、設定する
vim ./server.properties

# 最後起動
java -Xmx2048M -Xms1024M -jar forge-1.8-11.14.3.1450-universal.jar
  • server.propertiesの詳細はここあたり見る。
  • MODのjarファイルは、「mods」というディレクトリがあるので、その中に入れる。
    • クライアント側のmodsディレクトリにも、同じファイルを入れなければならないので注意。
    • クライアント側のmodsディレクトリ無いよって方は、forgeをクライアント側にインストールしてないとかじゃないかな

最近Minecraft Server Managerなるものも見つけたので、こっちもできたら確認したいなあ。

クライアント側も書こうと思ったけどブログ書くの面倒臭かったので省く…。

MacでSphinxインストールしてモダンなsphinx_rtd_theme使ってみたのと簡易自動ビルド

いろいろ調べてる時、なんかよくAPIドキュメントでこういう感じ(↓)のデザインのドキュメントを見ると思ってたんですけど、 sphinx_rtd_themeっていうSphinxのテーマでした。知らんかった。

f:id:esperia:20150704100936p:plain

Powerline Documentation

Sphinxっていうのは、ドキュメントを掻くためのツールです。一言で言うと静的なWikiみたいな感じ。reStructuredTextという記法でドキュメントを書いた後ビルドを行うと、静的なHTMLドキュメントが生成されます。"静的"なのが特徴で、PHPみたいなサーバサイドで動くソフトウェアとか入ってなくても、index.htmlをダブルクリックするだけでドキュメントが表示されます。簡単にいい感じのドキュメント作ろうと思うと選択肢としてはとっても良いものです!

で、ちょっと以前作ったスクリプトもなんとなく使うことが多いので、ブログに収めておこうかと思いました。

Sphinxのインストール

# Homebrew(http://brew.sh/)はあらかじめ入れておく。

# pythonとpipのインストール
brew update
brew install python

# Sphinxのインストール
pip install sphinx

# sphinx_rtd_themeのインストール
#pip install sphinx_rtd_theme

僕だけかもしれないんですが、Googleの検索結果でsphinx-users.jpのドキュメントが一番上に来ます。ただこっちは既に古くなっているみたいで、今はsphinx-docs.orgの方が最新です。日本語はこっちsphinx-users.jpではeasy_installを使ったインストールが解説されていますが、現在はpipの方がベターなパッケージ管理ツールなので、こちらを使います。

現在、pip install sphinx_rtd_themeは、sphinxの依存関係に含まれているので、pipでsphinx入れただけでsphinx_rtd_themeもインストールされます。

プロジェクトの作成とビルド

# フォルダを作ってその中に入る
mkdir docs
cd docs

# 実行
sphinx-quickstart

対話形式でたくさん質問される。でも基本全部デフォルト(訊かれてもEnterキー押しておく)で大丈夫。必須項目だけ載せておく

The project name will occur in several places in the built documentation.
> Project name:
my-delicious-docs # 入力

> Author name(s):
esperia # 入力

Sphinx has the notion of a "version" and a "release" for the
software. Each version can have multiple releases. For example, for
Python the version is something like 2.5 or 3.0, while the release is
something like 2.5.1 or 3.0a1.  If you don't need this dual structure,
just set both to the same value.
> Project version:
0.1.0 # 入力

For a list of supported codes, see
http://sphinx-doc.org/config.html#confval-language.
> Project language [en]:
ja # 入力

テーマを入れ替えてビルド

conf.pyを開いて、以下の様に修正。

# ...省略...

import sys
import os
import shlex
import sphinx_rtd_theme # 追加

# ...省略...

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#html_theme = 'alabaster' # コメントアウト
html_theme = 'sphinx_rtd_theme' # 追加

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # 編集

そして、下記のコマンドを入力してビルド!

# ビルド
make html

f:id:esperia:20150704131016p:plain

おおお!!

編集したら自動的にビルドできるようにする

ここからはおまけです。 Sphinxってビルドいちいちめんどくさいんですよね。編集したらビルド、編集したらビルド…を繰り返すので。 で、結構前なんですが、node.jsとgruntを使って、編集するファイルを監視し、ファイルが変更されたら自動的にmake htmlを実行する方法があるので、こちらもせっかくなので日記に記します。

まずはnode.jsをインストールします。

# nodebrewのインストール(https://github.com/hokaccha/nodebrew)
curl -L git.io/nodebrew | perl - setup
echo "export PATH=$HOME/.nodebrew/current/bin:$PATH" >> ~/.bashrc

# node.jsとnpmインストール
nodebrew install-binary latest
nodebrew use latest
npm -v

npm initを入力してpackage.jsonを作成します。いろいろ訊かれますが、全部EnterキーでOKです。

npm init

続けてgruntとgrunt-contrib-watchプラグインをインストールします。

npm install -g grunt-cli
npm install grunt --save-dev
npm install grunt-contrib-watch --save-dev

スクリプトをダウンロードして、実行します。

# https://gist.github.com/esperia/698c089861ab9d246940 のスクリプト
curl -O -L https://gist.githubusercontent.com/esperia/698c089861ab9d246940/raw/2054d7f285e9636fb48bf0ff388f9d07a578252d/Gruntfile.js

# ファイルの変更を監視
grunt watch

この状態で各種*.rstを編集すると、自動的にmake htmlが実行されます! sphinx自体だったりにこういう仕組みは既にあるのかもしれないんですが、同じ方法で実行している人も居るし、そんなもんなんじゃないかなと思ったりはしてます。 解決方法の一つとして。

libGDXのテクスチャをdisposeするためだけにフィールド変数作るのめんどくさいので、管理クラスあってもいいんじゃないかなあ、という話

追記2(2015-06-18 14:47)

AssetManagerを使うと、本稿の問題は解決できました!僕が管理クラスの存在を知らなかっただけでした。

調べたのでサンプルコードを載せておきます。

public class MyGdxGame extends ApplicationAdapter {

    // 読み込むファイルのパス
    private static String FILE_MYFILE = "myfile.png";
    private AssetManager am = new AssetManager();

    private SpriteBatch batch;
    private Animation anim;
    private float time = 0.f;

    @Override
    public void create() {
        batch = new SpriteBatch();

        // 読み込ませる
        am.load(FILE_MYFILE, Texture.class);
        // 非同期で読込み中であるため、読込みが全て終わるまで待つ
        am.finishLoading();

        // 読み込んだテクスチャを取得
        Texture texture = am.get(FILE_MYFILE, Texture.class);
        TextureRegion[][] split = TextureRegion.split(texture, 64, 64);
        anim = new Animation(0.05f, split[0]);
    }

    @Override
    public void render() {
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        time += Gdx.graphics.getDeltaTime();
        batch.begin();
        batch.draw(anim.getKeyFrame(time), 10, 10);
        batch.end();
    }

    @Override
    public void dispose() {
        am.dispose(); // 破棄
    }

}

AssetManagerを使うと、テクスチャの読み込みから破棄までを管理してくれるようです。 さらに、読み込みを非同期で行う仕組みがあり、テクスチャの読み込みに時間がかかる場合にも使えそうな感じです。

どうやってAssetManager#dispose()時に各クラスのdispose()メソッド呼んでるのかなと思ってソース見ると、Disposableインターフェースを継承してる場合はdispose()メソッド呼ぶみたいな処理になってました。なるほど。

ついでに会社ブログの実装の方も修正しておこう…

追記(2015-06-17 14:24)

AssetsManager知らなかった。。標準であるもんですね!まだちょっと使ってみてはいないんですが、僕の欲しいもの+αっぽいです。 使ったら追記します!

本題

使えるかどうか分かんないんですが。

libGDXで遊んでて思ってたんですけど、TextureとかBitmapFontとかって、newして他のクラス渡したり、TextureRegionへ分割したりした後、最後にdispose(破棄)するためだけにフィールド変数に持ってる場合ってわりとある気がしてるんですね。

例えばこんな感じ。

public class MyGdxGame extends ApplicationAdapter {

    private Texture texture; // disposeのためだけに持ってる
    private SpriteBatch batch;
    private Animation anim;
    private float time = 0.f;

    @Override
    public void create() {
        batch = new SpriteBatch();

        texture = new Texture(Gdx.files.internal("myfile.png")); // 読み込み
        TextureRegion[][] split = TextureRegion.split(texture, 64, 64);
        anim = new Animation(0.05f, split[0]);
    }

    @Override
    public void render() {
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        time += Gdx.graphics.getDeltaTime();
        batch.begin();
        batch.draw(anim.getKeyFrame(time), 10, 10);
        batch.end();
    }

    @Override
    public void dispose() {
        texture.dispose(); // 破棄
    }
}

そうすると、dispose()呼ぶためだけに、Textureインスタンスをフィールド変数に保持しておかなきゃならない。だったら、それらをまとめて配列みたいなので管理させておいて、disposeするべきタイミングで一気にdispose、ってのもありなんじゃないのかなあと思ったりしたのです。

実装してみる

例えば、こんなクラスを作っておいて。

package com.esperia09.libgdx.utils;

import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;

public class DisposeRegister implements Disposable {

    private final Array<Disposable> disposables = new Array<Disposable>();

    public <T extends Disposable> T reg(T obj) {
        disposables.add(obj);
        return obj;
    }

    @Override
    public void dispose() {
        for (Disposable d : disposables) {
            d.dispose();
        }
        disposables.clear();
    }
}

そして、上記クラスをこう使います。

public class MyGdxGame2 extends ApplicationAdapter {

    private DisposeRegister dr; // 追加
    private SpriteBatch batch;
    private Animation anim;
    private float time = 0.f;

    @Override
    public void create() {
        batch = new SpriteBatch();
        dr = new DisposeRegister(); // 追加

        Texture texture = dr.reg(new Texture(Gdx.files.internal("myfile.png"))); // 変更
        TextureRegion[][] split = TextureRegion.split(texture, 64, 64);
        anim = new Animation(0.05f, split[0]);

    }

    @Override
    public void render() {
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        time += Gdx.graphics.getDeltaTime();
        batch.begin();
        batch.draw(anim.getKeyFrame(time), 10, 10);
        batch.end();
    }

    @Override
    public void dispose() {
        dr.dispose(); // 変更
    }
}

こうすると、new Texture(...)dr.reg(new Texture(...))みたいに囲むだけで、配列に登録し、任意の箇所で一気にdisposeできます。上記ではTexture一つだけですが、複数になると結構コード量変わってくると思います。

こんな感じで、disposeさせるためにインスタンス管理するのってありなんじゃないかなあと思っている次第です。

一抹の不安

ただ、これがベストなんだったら、標準で用意されてたり、他でもこういうの普通にされてるんじゃないかなと思ったりはします。なので、僕がありかなと思ってるだけで、実はタブーだったり、Textureの管理の仕方がヘタクソだったりするのかなあとも思ってます。ちなみにQiitaに投稿しなかったのはこの辺りが理由。

シンプルなコード書くの難しいですね。