https://github.com/reputeless/siv3dexamples-ipsj17
情報処理 2017 年 6 月号「音や画像で遊ぼう」サンプルコード
https://github.com/reputeless/siv3dexamples-ipsj17
Last synced: about 23 hours ago
JSON representation
情報処理 2017 年 6 月号「音や画像で遊ぼう」サンプルコード
- Host: GitHub
- URL: https://github.com/reputeless/siv3dexamples-ipsj17
- Owner: Reputeless
- License: mit
- Created: 2017-02-26T16:18:25.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2017-05-10T02:29:17.000Z (about 8 years ago)
- Last Synced: 2025-02-21T08:47:16.774Z (4 months ago)
- Homepage:
- Size: 6.84 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
## 音や画像で遊ぼう ~インタラクティブアプリケーションのための C++ フレームワーク「Siv3D」~
サンプルコード(『情報処理』2017 年 6 月号 掲載)### Siv3D のインストール方法 (Windows)
Siv3D Web ページ https://github.com/Siv3D/Reference-JP/wiki/ダウンロードとインストール## 1. コンピュータ画伯
```cpp
# include// ① 2つの画像の差分を計算
double Diff(const Image& a, const Image& b)
{
double d = 0.0;for (auto p : step(a.size))
{
d += Abs(int(a[p].r) - int(b[p].r));
d += Abs(int(a[p].g) - int(b[p].g));
d += Abs(int(a[p].b) - int(b[p].b));
}return d;
}void Main()
{
// ② 目標とする画像を開く
const Image target = Dialog::OpenImage().fit(Window::Size());// ③ 同じ大きさの白い画像を用意
Image image(target.size, Palette::White);
Image old = image;
DynamicTexture texture(old);double d1 = Diff(target, image); // ④
while (System::Update())
{
for (int i = 0; i < 100; ++i)
{
old = image; // ⑤// ⑥ 画像内のランダムな位置
Point pos = RandomPoint(image.width, image.height);// ⑦ ランダムな色
ColorF color;
color.r = Random();
color.g = Random();
color.b = Random();
color.a = Random();// ⑧ ランダムな大きさ
int size = Random(1, 10);// ⑨ 円を描いてみる
Circle(pos, size).write(image, color);// ⑩ 目標に近づけば採用
double d2 = Diff(target, image);
if (d2 < d1)
{
d1 = d2;
}
else
{
image = old; // ⑪
}
}// ⑫ テクスチャを更新して描画
texture.fill(image);
texture.draw();
}
}
```## 2. あなたの声はどんな形
```cpp
# includevoid Main()
{
// ① マイク録音開始
Recorder mic;
mic.open(0, 5s, RecordingFormat::S44100, true);
mic.start();// ② 加算ブレンドを有効に
Graphics2D::SetBlendState(BlendState::Additive);while (System::Update())
{
// ③ FFT で周波数成分を解析
const auto fft = FFT::Analyze(mic);for (int i = 0; i < fft.length(); ++i)
{
// ④ 音階
double s = Log2((fft.resolution() * (i + 1)) / 27.5);// ⑤ パワー
double p = fft.buffer[i];// ⑥ 円の中心位置
const Vec2 pos = Window::Center() + Circular(Pow(p, 0.5) * 600, s * TwoPi);// ⑦ 円の色
const Color c = HSV(s * 360).toColorF(0.05 * s);// ⑧ 円を描く
Circle(pos, 15 - s).draw(c);
}
}
}
```## 3. 幸せになれる画像ビューア
```cpp
# include// ① コメントの文章と位置
struct Comment
{
String text;
Vec2 pos;
};void Main()
{
// ② 画像を選択する
Texture photo(Dialog::OpenImage().fit(Window::Size()));// ③ 事前に用意したコメントを読み込む
TextReader reader(L"comments.txt");
Array comments;
Comment c;
while (reader.readLine(c.text))
{
c.pos.x = Random(1000, 2000); // ④
c.pos.y = Random(0, 420);
comments.push_back(c);
}// ⑤ コメント用のフォント
Font font(30, Typeface::Bold, FontStyle::Outline);
font.changeOutlineStyle(TextOutlineStyle(Palette::Gray, Palette::White, 1));while (System::Update())
{
photo.draw(); // ⑥for (auto& c : comments)
{
font(c.text).draw(c.pos); // ⑦
// ⑧ コメントを左に流す
c.pos.x -= 4 + c.text.length * 0.2;// ⑨ 画面外に出たらまた右へ
if (c.pos.x < -500)
{
c.pos.x = Random(1000, 2000);
c.pos.y = Random(0, 420);
}
}
}
}
```## 4. めちゃくちゃな音楽プレイヤ
```cpp
# includevoid Main()
{
// ① 表示用のフォントを用意
Font font(20);// ② 音楽ファイルを開く
Sound sound = Dialog::OpenSound();// ③ 音楽を再生
sound.play();while (System::Update())
{
// ④ 線を描く
Line(0, 240, 640, 240).draw(4);
Line(320, 480, 320, 0).draw(4);// ⑤ カーソルの位置に円を描く
Point pos = Mouse::Pos();
Circle(pos, 20).draw(Palette::Orange);// ⑥ テンポを計算
double tempo = Exp2((pos.x - 320) / 240.0);// ⑦ ピッチを計算
double pitch = -(pos.y - 240) / 60.0;// ⑧ 音楽にテンポとピッチを適用
sound.changeTempo(tempo);
sound.changePitchSemitones(pitch);// ⑨ 現在のテンポとピッチを表示
font(L"tempo: ", tempo).draw(20, 20);
font(L"pitch: ", pitch).draw(20, 60);
}
}
```## 5. 数式の大地を探検する
> :warning: Release ビルドで、「デバッグなしで実行」をしないとちょっと重いです。
```cpp
# includevoid Main()
{
// ① 背景を明るい色に
Graphics::SetBackground(Color(120, 180, 160));// ② メッシュを用意
MeshData meshData = MeshData::Grid(25, 160);
DynamicMesh mesh(meshData);// ③ 数式を入力するテキストエリアを用意
GUI gui(GUIStyle::Default);
gui.addln(L"exp", GUITextArea::Create(2, 30));while (System::Update())
{
if (!gui.textArea(L"exp").active)
{
Graphics3D::FreeCamera(); // ④
}// ⑤ 数式が変更されたら
if (gui.textArea(L"exp").hasChanged)
{
if (const ParsedExpression exp{ gui.textArea(L"exp").text })
{
gui.textArea(L"exp").style.color = Palette::Black; // ⑥
// ⑦ 数式に基づきメッシュの座標を計算
for (auto& v : meshData.vertices)
{
v.position.y = exp.evaluateOpt({
{ L"x", v.position.x },
{ L"y", v.position.z } })
.value_or(0);
}// ⑧ 法線を更新
meshData.computeNormals();// ⑨ メッシュを更新
mesh.fillVertices(meshData.vertices);
}
else
{
gui.textArea(L"exp").style.color = Palette::Red; // ⑩
}
}// ⑪ メッシュを描画
mesh.draw().drawShadow();
}
}
```