Hello World / plɹoM ollǝH

Programmers Live in Vain

C++構造体のXmlシリアライザを自動生成したい

C#だったら属性を書くだけで済むけれど、C++はそういうわけにはいかないのでXMLで定義したフォーマットからコードを生成するスクリプトを書いた。

まずはデータフォーマットをXmlで表記する。

<?xml version='1.0' encoding='UTF-8'?>
<Root>
    <Type name="Scene">
        <Type name="Material">
            <Type name="Property">
                <value name="Name" type="String"/>
                <value name="Value" type="Float[]"/>
            </Type>
            <value name="Name" type="String"/>
            <value name="Properties" type="Property{}"/>
        </Type>
        <Type name="Mesh">
            <Type name="Vertex">
                <value name="Position" type="Float[]"/>
            </Type>
            <value name="Name" type="String"/>
            <value name="Vertices" type="Vertex[]"/>
            <value name="Indices" type="Integer[]"/>
        </Type>
        <Type name="Model">
            <value name="Name" type="String"/>
            <value name="Material" type="String"/>
            <value name="Mesh" type="String"/>
        </Type>
        <value name="Name" type="String"/>
        <value name="Materials" type="Material{}"/>
        <value name="Meshes" type="Mesh{}"/>
        <value name="Models" type="Model{}"/>
    </Type>
</Root>

このXMLからは次のようなC++コードが生成される

struct Scene {
    struct Material {
        struct Property {
            std::string name;
            std::vector< float > value;
        };

        std::string name;
        std::map< std::string, Property > properties;
    };

    struct Mesh {
        struct Vertex {
            std::vector< float > position;
        };

        std::string name;
        std::vector< Vertex > vertices;
        std::vector< int > indices;
    };

    struct Model {
        std::string name;
        std::string material;
        std::string mesh;
    };

    std::string name;
    std::map< std::string, Material > materials;
    std::map< std::string, Mesh > meshes;
    std::map< std::string, Model > models;
};

void serialize(tinyxml2::XMLElement* out_xml, const Scene::Material::Property& in_value);
void deserialize(Scene::Material::Property& out_value, const tinyxml2::XMLElement* in_xml);
void serialize(tinyxml2::XMLElement* out_xml, const Scene::Material& in_value);
void deserialize(Scene::Material& out_value, const tinyxml2::XMLElement* in_xml);
void serialize(tinyxml2::XMLElement* out_xml, const Scene::Mesh::Vertex& in_value);
void deserialize(Scene::Mesh::Vertex& out_value, const tinyxml2::XMLElement* in_xml);
void serialize(tinyxml2::XMLElement* out_xml, const Scene::Mesh& in_value);
void deserialize(Scene::Mesh& out_value, const tinyxml2::XMLElement* in_xml);
void serialize(tinyxml2::XMLElement* out_xml, const Scene::Model& in_value);
void deserialize(Scene::Model& out_value, const tinyxml2::XMLElement* in_xml);
void serialize(tinyxml2::XMLElement* out_xml, const Scene& in_value);
void deserialize(Scene& out_value, const tinyxml2::XMLElement* in_xml);

で、次のようなデータを読み込むことが可能になり

<?xml version='1.0' encoding='UTF-8'?>
<Scene>
  <Name>PRIMITIVES</Name>
    <Materials>
        <Material>
            <Name>RED</Name>
            <Properties>
                <Property>
                    <Name>Diffuse</Name>
                    <value>
                        <Float>1.0</Float>
                        <Float>0.0</Float>
                        <Float>0.0</Float>
                        <Float>1.0</Float>
                    </value>
                </Property>
            </Properties>
        </Material>
    </Materials>
    <Meshes>
        <Mesh>
            <Name>TRIANGLE</Name>
            <Vertices>
                <Vertex>
                    <Position>
                        <Float>0.0</Float>
                        <Float>1.0</Float>
                        <Float>0.0</Float>
                    </Position>
                    <Position>
                        <Float>-0.866</Float>
                        <Float>-0.5</Float>
                        <Float>0.0</Float>
                    </Position>
                    <Position>
                        <Float>0.866</Float>
                        <Float>-0.5</Float>
                        <Float>0.0</Float>
                    </Position>
                </Vertex>
            </Vertices>
            <Indices>
                <Uint>0</Uint>
                <Uint>1</Uint>
                <Uint>2</Uint>
            </Indices>
        </Mesh>
    </Meshes>
    <Models>
        <Model>
            <Name>TRIANGLE_RED</Name>
            <Material>RED</Material>
            <Mesh>TRIANGLE</Mesh>
        </Model>
    </Models>
</Scene>

次のように使う。

int main()
{
    Scene scene;

    // 読み込み
    tinyxml2::XMLDocument doc;
    doc.LoadFile("deserialize_test.xml");
    deserialize(scene, doc.FirstChildElement("Scene"));

    // 書き込み
    tinyxml2::XMLDocument doc2;
    auto* elem = doc2.NewElement("Scene");
    doc2.InsertFirstChild(elem);
    serialize(elem, scene);
    doc2.SaveFile("serialize_test.xml");

    return 0;
}

おとなしくflatbuffersを使ってね

TransBook T90Chi T90CHI-32G を買ったあとやった事

コード書き専用マシンとして ¥30,000 で購入

不要なソフトウェアを削除
Windows10 にアップグレード
Visual Studio Community 2015 をインストー
  • Custom → C++ のみ選択

容量が32GBなので死にそう。SDカード買って仮想HD化する予定

ffmpeg flv to mp4

ffmpegを使ってflvをコンバートしたら動画がカクカクになってしまったのでメモ

環境

Windows 8.1 + ffmpeg static build

現象
  • WMPではカクカクする
  • GOM Playerで見ると普通の動画に見える
  • Chromeではスローモーション再生
  • 詳細情報を見るとフレームレートが1000になっている
  • FLVのフレームレートは30とか普通の数字
テスト
ffmpeg -i test.flv test_raw.mp4
ffmpeg -i test.flv -vcodec mpeg4 test_codec.mp4
ffmpeg -i test.flv -r 60 -vcodec h264 test_60fps.mp4
ffmpeg -i test.flv -vsync passthrough test_vsync.mp4
結果
  1. 引数なしはカクカクな動画ができる (コーデックはh264)
  2. ビデオコーデックをmpeg4にするとカクカクしないけど汚い
  3. 明示的にビデオコーデックとフレームレートを指定すると解決した
  4. -vsync passthroughオプションでfpsがいい感じに設定されるっぽい

QPixmap from PIL Image

PILで作った画像を表示するときに便利

f:id:dungeonneko:20150719142409p:plain

# conding: utf-8
import sys
from PySide.QtCore import *
from PySide.QtGui import *
from PIL import Image, ImageQt

# entry point
if __name__ == '__main__':
    myapp = QApplication(sys.argv)

    # PILで画像読み込み
    img = Image.open('temp.png')

    # Qtで表示
    pm = QPixmap.fromImage(ImageQt.ImageQt(img))
    lbl = QLabel()
    lbl.setPixmap(pm)
    lbl.show()

    sys.exit(myapp.exec_())

PySide Dock配置とメニューからの表示切替

よく使うので自分用にメモ

f:id:dungeonneko:20150719123918p:plain

# conding: utf-8
import sys
from PySide.QtCore import *
from PySide.QtGui import *

# entry point
if __name__ == '__main__':
    myapp = QApplication(sys.argv)
    wnd = QMainWindow()

    # Dock Widgets
    wnd.__c = QTextEdit(wnd)
    wnd.__l = QDockWidget("Left", wnd)
    wnd.__r = QDockWidget("Right", wnd)
    wnd.__t = QDockWidget("Top", wnd)
    wnd.__b = QDockWidget("Bottom", wnd)

    wnd.setCentralWidget(wnd.__c)
    wnd.addDockWidget(Qt.LeftDockWidgetArea,   wnd.__l)
    wnd.addDockWidget(Qt.RightDockWidgetArea,  wnd.__r)
    wnd.addDockWidget(Qt.TopDockWidgetArea,    wnd.__t)
    wnd.addDockWidget(Qt.BottomDockWidgetArea, wnd.__b)
    wnd.setWindowTitle('gui example')
    wnd.statusBar()

    # Exit Action
    actionExit = QAction('&Exit', wnd)
    actionExit.setShortcut('Ctrl+Q')
    actionExit.setStatusTip('Quit application')
    actionExit.triggered.connect(wnd.close)
    m = wnd.menuBar().addMenu('&File')
    m.addAction(actionExit)
    t = wnd.addToolBar('Exit')
    t.addAction(actionExit)

    # Window Menu: toggle widget's visibility
    m = wnd.menuBar().addMenu('&Window')
    m.addAction(wnd.__l.toggleViewAction())
    m.addAction(wnd.__r.toggleViewAction())
    m.addAction(wnd.__t.toggleViewAction())
    m.addAction(wnd.__b.toggleViewAction())

    wnd.resize(640, 480)
    wnd.show()
    sys.exit(myapp.exec_())

DirectXでOBJファイル表示

DirectXOBJファイルを表示する。

f:id:dungeonneko:20150712015318p:plain

時間はかけたくないのでライブラリ3Dデータを使う。

こんな感じで簡単に読み込み処理が書ける。

#include "tiny_obj_loader.h"

void CreateBuffer(ID3D11Buffer** io_buf, UINT in_byteWidth, UINT in_bindFlags, const void* in_data)
{
    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = in_byteWidth;
    bd.BindFlags = in_bindFlags;
    bd.CPUAccessFlags = 0;
    D3D11_SUBRESOURCE_DATA InitData;
    ZeroMemory(&InitData, sizeof(InitData));
    InitData.pSysMem = in_data;
    g_pd3dDevice->CreateBuffer(&bd, &InitData, io_buf);
}

void Load(const char* in_path)
{
    std::vector<tinyobj::shape_t> shapes;
    std::vector<tinyobj::material_t> materials;

    // OBJファイル読み込み
    std::string err = LoadObj(shapes, materials, in_path.c_str());
    if (!err.empty()) return;

    CreateBuffer(&g_vb, mesh.positions.size() * sizeof(float), D3D11_BIND_VERTEX_BUFFER, &mesh.positions[0]);
    CreateBuffer(&g_ib, mesh.indices.size() * sizeof(unsigned int), D3D11_BIND_INDEX_BUFFER, &mesh.indices[0]);
}

とりあえず自分で作ったテクスチャを貼れるようにしたい。

Node Graphでテクスチャ生成

f:id:dungeonneko:20150630230337p:plain

Substance買うお金無い

Python

# conding: utf-8
import math
from PIL import Image

PI = 3.1415926536

# 正弦
class Sin:
    def __init__(self, in_x):
        self.x = in_x
    def __call__(self):
        return math.sin(self.x())

# 余弦
class Cos:
    def __init__(self, in_x):
        self.x = in_x
    def __call__(self):
        return math.cos(self.x())

# 最大
class Max:
    def __init__(self, in_x, in_y):
        self.x = in_x
        self.y = in_y
    def __call__(self):
        x = self.x()
        y = self.y()
        return x if x >= y else y

# 束縛
class Const:
    def __init__(self, in_value):
        self.value = in_value
    def __call__(self):
        return self.value

# 加算
class Add:
    def __init__(self, in_x, in_y):
        self.x = in_x
        self.y = in_y
    def __call__(self):
        return self.x() + self.y()

# 減算
class Sub:
    def __init__(self, in_x, in_y):
        self.x = in_x
        self.y = in_y
    def __call__(self):
        return self.x() - self.y()

# 乗算
class Mul:
    def __init__(self, in_x, in_y):
        self.x = in_x
        self.y = in_y
    def __call__(self):
        return self.x() * self.y()

img = Image.new("L", (256, 256))
p = img.load()
for y in range(256):
    for x in range(256):
        u = Const(x / 256.0)
        v = Const(1.0 - (y / 256.0))
        r  = Const(2.0 * PI * -0.02)
        s = Sub(Mul(u, Cos(r)), Mul(v, Sin(r)))
        t = Add(Mul(v, Cos(r)), Mul(u, Sin(r)))
        freq = Const(2.0 * PI * 10.0)
        lhs = Cos(Mul(s, freq))
        rhs = Cos(Mul(t, freq))
        F = Max(lhs, rhs)
        p[ x, y ] = int(F() * 255)
img.show()