「 Rust で書かれた GUI である conrod を使ってみようぜ☆?」
RustでGUI 〜conrod編〜
Module conrod::guide::chapter_1
「 というか Piston というゲームエンジンを使った方が早くないか☆?」
「 ↑ 作る側の気持ちになって思考をたどれば、 input にあるのがすべてだろ☆」
「 ドキュメントが全然くわしくないんで ダウンロードしたソースでも眺めるか……☆」
「 ゲームパッドが抜けているわけでもないが、マウスとキーボードの入力は入るが ゲームパッドには反応しないぜ☆」
Start a cross platform library for controller input #884
「 ゲームパッドがなぜ反応しないのか分からないので、他のサンプルを見てみようぜ☆?」
「 だいたい、ゲームパッドが動きません、とか質問したら わたしのところは動く、と言われて終わるんで、
もう少し 詳しい状況を知りたいぜ☆」
「 お父ん さっきから サンプル叩きまくってるが、
ウィルス・ソフトが入ってたら やられたい放題だぜ☆」
「 そんなことがあったら 2台目のパソコンで暴れ回るからな☆」
「 こんなサンプル いくら動かしたって、ゲームパッドは解決しなくない?」
「 サンプルは動かしたが お前んとこのゲームパッドは動かねーっ、と暴れるための下ごしらえだぜ☆」
「 そんな下ごしらえしてないで 今すぐ 暴れたらどうだぜ☆?」
「 ゲームパッドに対応していないゲームエンジン使うの わらう☆」
Testing joystick with "user_input" example #310
「 ↑ ゲームパッドは難しすぎて piston 未対応かだぜ☆ ゲームパッドだけ別ライブラリを使えばいいのかだぜ……☆」
「 Rust 純正には Windows PC 用の日本のサードパーティー製のゲームパッドが使えるライブラリが無いのかもしらん☆
マイクロソフトが Rust言語で書き直さないと無理だろ☆」
「 piston でゲームパッドが使えないのは つらたん☆
じゃあ次は ゲームエンジン godot を調べてみるか……☆」
「 ゲームエンジン piston で、ゲームを作らずに ドット絵エディターを作ったらいいんじゃないか☆?」
How to save a PNG image in Rust?
「 ↑ まず ゲーム・ウィンドウを PNG 画像にして出力できるか調べようぜ☆?」
extern crate image;
fn write_image() {
let buffer: &[u8] = ...; // Generate the image data
// Save the buffer as "image.png"
image::save_buffer(&Path::new("image.png"), buffer, 800, 600, image::RGBA(8))
}
「 どうやって 8bit サイズの非負の整数の配列を作るんだぜ☆?」
Writing a Raytracer in Rust: part 1 - the Piston maze
extern crate image;
extern crate piston_window;
use piston_window::EventLoop;
const WIDTH: u32 = 1280;
const HEIGHT: u32 = 720;
fn main() {
let frame_buffer = image::ImageBuffer::from_pixel(WIDTH, HEIGHT, image::Rgba([0,0,0,255]));
let mut window: piston_window::PistonWindow =
piston_window::WindowSettings::new("Raytracer", [WIDTH, HEIGHT])
.exit_on_esc(true)
.build()
.unwrap_or_else(|_e| { panic!("Could not create window!")});
let tex = piston_window::Texture::from_image(
&mut window.create_texture_context(),
&frame_buffer,
&piston_window::TextureSettings::new())
.unwrap();
window.set_lazy(true);
while let Some(e) = window.next() {
window.draw_2d(&e, |c, g, _| {
piston_window::clear([1.0; 4], g);
piston_window::image(&tex, c.transform, g)
});
}
}
「 ↑ piston の Texture は 画像を読み込めるみたいなんで、対称性を考えれば 書き出すのも Texture だろ☆
Texture の API を調べてみようぜ☆?」
/// Implemented by textures for updating.
pub trait UpdateTexture<F>: TextureOp<F> + ImageSize + Sized {
/// Update the texture.
///
/// The `offset` and `size` arguments represent the position and dimensions of the sub-section
/// of the texture that is to be updated with the given `memory`.
fn update<O, S>(
&mut self,
factory: &mut F,
format: Format,
memory: &[u8],
offset: O,
size: S,
) -> Result<(), Self::Error>
where O: Into<[u32; 2]>,
S: Into<[u32; 2]>;
}
「 ↑ memory に 8bit 型配列が入ってるよな☆」
「 じゃあ テクスチャーに入れる前に メモリーを作っておけばいいか……☆」
extern crate image;
use image::*;
use std::path::Path;
fn main() {
// 灰色のドット1つ分だぜ☆(^~^)
let buffer: &[u8] = &[128, 128, 128, 128];
// Save the buffer as "image.png"
image::save_buffer(
&Path::new("output/gray-1dot.png"),
buffer,
1,
1,
ColorType::Rgba8,
)
.unwrap();
}
「 1 ドットじゃ やってらんないわね。 32 x 32 サイズの png 画像を出力してみましょう!」
extern crate image;
use image::*;
use std::path::Path;
fn main() {
// 灰色のドット1つ分だぜ☆(^~^)
{
let buffer: &[u8] = &[128, 128, 128, 128];
image::save_buffer(
&Path::new("output/gray-1dot.png"),
buffer,
1,
1,
ColorType::Rgba8,
)
.unwrap();
}
// 次はベクターで☆(^~^)
{
let gray = &Dot {
r: 128,
g: 128,
b: 128,
a: 128,
}
.array();
let red = &Dot {
r: 204,
g: 51,
b: 51,
a: 255,
}
.array();
let mut vec: Vec<u8> = Vec::new();
vec.extend_from_slice(red);
vec.extend_from_slice(gray);
vec.extend_from_slice(gray);
vec.extend_from_slice(red);
image::save_buffer(
&Path::new("output/ichimatsu.png"),
&vec,
2,
2,
ColorType::Rgba8,
)
.unwrap();
}
}
struct Dot {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Dot {
pub fn array(&self) -> [u8; 4] {
[self.r, self.g, self.b, self.a]
}
}
「 ↑ こんな感じで ドット絵は出力できそうなんで、あとはインターフェースだけの問題だな☆」
// サイズ指定で☆(^~^)
{
let frame = Frame::new(32, 64);
image::save_buffer(
&Path::new("output/32x64.png"),
&frame.to_vec(),
frame.width,
frame.height,
ColorType::Rgba8,
)
.unwrap();
}![20200416piston14.png](https://crieit.now.sh/upload_images/09be0ae4c8c329327bf5a25b87f0c8ef5e984dda7a5b8.png)
struct Frame {
pub dots: Vec<Dot>,
pub width: u32,
pub height: u32,
}
impl Frame {
pub fn new(width: u32, height: u32) -> Self {
Frame {
dots: vec![Dot::default(); (width * height) as usize],
width: width,
height: height,
}
}
pub fn to_vec(&self) -> Vec<u8> {
let mut vec: Vec<u8> = Vec::new();
for dot in &self.dots {
vec.extend_from_slice(&dot.array());
}
vec
}
}
#[derive(Clone)]
struct Dot {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Dot {
pub fn array(&self) -> [u8; 4] {
[self.r, self.g, self.b, self.a]
}
}
impl Default for Dot {
fn default() -> Self {
Dot {
r: 0,
g: 128,
b: 128,
a: 255,
}
}
}
「 JSON とか めんどくさい☆ さっさと ドット絵エディター・プロジェクトを起ち上げろだぜ☆」
「 ↑ ここまでは さくっと作れるよな☆ むずかしいのは画面遷移だぜ☆」
「 piston と godot が合体してりゃ楽なんだが、あっちに在るものは こっちに無い☆
piston の画面遷移を調べるか……☆」
「 piston のドキュメントは何もないといっていいぐらい何もないぜ☆」
「 どっかに コントロールのサンプルがあっただろ、探そうぜ☆?」
Intro to Rust-lang (Games and Graphics with Piston; Pong game)
GUI Widget Framework Written In Rust - Conrod Demo
couldn't find required command: "cmake"
「 ↑ conrod のサンプル ビルドするのに cmake がいるのかだぜ☆?」
「 なんで たった 24MB のファイルが 10分で落とせないんだぜ☆?」
couldn't find required command: "ninja"
【Chocolatey入門】導入から注意点、今後の可能性まで
「 ninja を入れるために chocolatey を入れる☆ chocolatey を入れるために 管理者権限のコマンドプロンプトで Power shell を実行する☆」
「 chocolatey は入ったが、ninja は入らない……☆」
C:\Program Files\ninja\bin\ninja.exe
「 こんな感じに置いて、システム環境変数の PATH に C:\Program Files\ninja\bin
を追加したら ninja 入った……☆
chocolatey 要らんぜ、消そ☆」
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
新しいクロスプラットフォームの PowerShell をお試しください https://aka.ms/pscore6
PS C:\WINDOWS\system32> cd C:\Users\むずでょ\source\repos\conrod
PS C:\Users\むずでょ\source\repos\conrod> cargo build
Compiling shaderc-sys v0.6.2
Compiling rendy-resource v0.5.1
Compiling rendy-command v0.5.1
Compiling conrod_core v0.69.0 (C:\Users\むずでょ\source\repos\conrod\conrod_core)
Compiling rendy-chain v0.5.1
Compiling wgpu-native v0.4.3
Compiling rusttype v0.7.9
Compiling vulkano v0.16.0
Compiling glutin v0.20.1
Compiling piston2d-graphics v0.30.0
Compiling glium v0.24.0
Compiling rendy-wsi v0.5.1
Compiling rendy-factory v0.5.1
error: failed to run custom build command for `shaderc-sys v0.6.2`
Caused by:
process didn't exit successfully: `C:\Users\むずでょ\source\repos\conrod\target\debug\build\shaderc-sys-4e702b4563a5e51c\build-script-build` (exit code: 101)
--- stderr
thread 'main' panicked at '
command did not execute successfully, got: exit code: 1
build script failed, must exit now', C:\Users\むずでょ\.cargo\registry\src\github.com-1ecc6299db9ec823\cmake-0.1.42\src\lib.rs:861:5
stack backtrace:
0: backtrace::backtrace::trace_unsynchronized
at C:\Users\VssAdministrator\.cargo\registry\src\github.com-1ecc6299db9ec823\backtrace-0.3.40\src\backtrace\mod.rs:66
1: std::sys_common::backtrace::_print_fmt
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\sys_common\backtrace.rs:77
2: std::sys_common::backtrace::_print::{{impl}}::fmt
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\sys_common\backtrace.rs:59
3: core::fmt::write
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libcore\fmt\mod.rs:1052
4: std::io::Write::write_fmt<std::sys::windows::stdio::Stderr>
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\io\mod.rs:1426
5: std::sys_common::backtrace::_print
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\sys_common\backtrace.rs:62
6: std::sys_common::backtrace::print
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\sys_common\backtrace.rs:49
7: std::panicking::default_hook::{{closure}}
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\panicking.rs:204
8: std::panicking::default_hook
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\panicking.rs:224
9: std::panicking::rust_panic_with_hook
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\panicking.rs:472
10: std::panicking::begin_panic_handler
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\panicking.rs:380
11: std::panicking::begin_panic_fmt
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\panicking.rs:334
12: cmake::fail
at C:\Users\むずでょ\.cargo\registry\src\github.com-1ecc6299db9ec823\cmake-0.1.42\src\lib.rs:861
13: cmake::run
at C:\Users\むずでょ\.cargo\registry\src\github.com-1ecc6299db9ec823\cmake-0.1.42\src\lib.rs:839
14: cmake::Config::build
at C:\Users\むずでょ\.cargo\registry\src\github.com-1ecc6299db9ec823\cmake-0.1.42\src\lib.rs:745
15: build_script_build::build_shaderc_msvc
at .\build\build.rs:76
16: build_script_build::main
at .\build\build.rs:255
17: std::rt::lang_start::{{closure}}<()>
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\src\libstd\rt.rs:67
18: std::rt::lang_start_internal::{{closure}}
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\rt.rs:52
19: std::panicking::try::do_call<closure-0,i32>
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\panicking.rs:305
20: panic_unwind::__rust_maybe_catch_panic
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libpanic_unwind\lib.rs:86
21: std::panicking::try
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\panicking.rs:281
22: std::panic::catch_unwind
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\panic.rs:394
23: std::rt::lang_start_internal
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\/src\libstd\rt.rs:51
24: std::rt::lang_start<()>
at /rustc/b8cedc00407a4c56a3bda1ed605c6fc166655447\src\libstd\rt.rs:67
25: main
26: invoke_main
at d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
27: __scrt_common_main_seh
at d:\agent\_work\3\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
28: BaseThreadInitThunk
29: RtlUserThreadStart
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
warning: build failed, waiting for other jobs to finish...
error: build failed
PS C:\Users\むずでょ\source\repos\conrod>
Checking rendy-graph v0.5.1
error: failed to run custom build command for `shaderc-sys v0.6.2`
Caused by:
process didn't exit successfully: `C:\Users\むずでょ\source\repos\conrod\target\debug\build\shaderc-sys-4e702b4563a5e51c\build-script-build` (exit code: 101)
--- stderr
CMake Warning (dev) at CMakeLists.txt:8 (project):
Policy CMP0048 is not set: project() command manages VERSION variables.
Run "cmake --help-policy CMP0048" for policy details. Use the cmake_policy
command to set the policy and suppress this warning.
The following variable(s) would be set to empty:
CMAKE_PROJECT_VERSION
CMAKE_PROJECT_VERSION_MAJOR
CMAKE_PROJECT_VERSION_MINOR
CMAKE_PROJECT_VERSION_PATCH
This warning is for project developers. Use -Wno-dev to suppress it.
PS C:\Users\むずでょ\source\repos\conrod> cmake /V
cmake version 3.17.1
set CMAKE_PROJECT_VERSION=3.17.1
set CMAKE_PROJECT_VERSION_MAJOR=3
set CMAKE_PROJECT_VERSION_MINOR=17
set CMAKE_PROJECT_VERSION_PATCH=1
cmake --help-policy CMP0048
「 ↑ 327 MB もある……☆ 残り3時間とか書いてる、タイムアウトしないかだぜ☆?」
「 --example
を使って実行☆ こんなコマンド誰が知ってるんだぜ☆?」
「 ダメだったぜ☆ ソースコードがでかすぎて、インポートして さくっと使えるライブラリという感じではないぜ☆」
「 GUI で画像サイズを入力させずに、JSON 書かせればいいんじゃないか☆?」
{
"file": "output/test_test.png",
"width": 32,
"height": 64
}
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
//! 設定ファイル
use serde::Deserialize;
use std::fs::File;
use std::io::Read;
use std::path::Path;
#[derive(Deserialize)]
#[serde(rename_all = "snake_case")] // プロパティ名が JSON 側でスネークケースであることを指定
pub struct Settings {
// 画像ファイルパス。assetsディレクトリーの下から。
pub file: String,
// 画像ファイルの横幅
pub width: u32,
// 画像ファイルの縦幅
pub height: u32,
}
impl Settings {
/// 設定ファイル読込。
pub fn load() -> Self {
let path = Path::new("./input/settings.json");
let mut file = match File::open(path) {
Ok(x) => x,
Err(err) => panic!("File open error. {:?}", err),
};
let mut contents = String::new();
match file.read_to_string(&mut contents) {
Ok(x) => x,
Err(err) => panic!("File open error. {:?}", err),
};
match serde_json::from_str(&contents) {
Ok(x) => x,
Err(err) => panic!("Unexpected settings: {}", err),
}
}
}
[https://docs.rs/conrod/0.61.1/conrod/backend/piston/draw/trait.Transformed.html#method.zoom](https://docs.rs/conrod/0.61.1/conrod/backend/piston/draw/trait.Transformed.html#method.zoom)
「 zoom という名前のメソッドはあるが Example が無い……☆」
「 どこでも いいから マウスでクリックしたら 画像を 真っ赤に塗りつぶしましょう!」
「 現存するソースから推測するしかないな☆ piston の開発者が生きてるかどうか知らんし☆」
// Event loop.
window.set_lazy(true);
while let Some(e) = window.next() {
// update
if let Some(_button) = e.press_args() {
println!("ボタンが押されたぜ☆(^~^)");
}
// draw
window.draw_2d(&e, |c, g, _| {
clear([1.0; 4], g);
image(&rust_logo, c.transform.zoom(2.0), g);
});
}
「 piston の Example がイケてないのは コード量が多くて どこを見れば サンプルのどこなのか分からんことだぜ☆」
「 ↑ 赤い矩形を出すだけなら これだけでいいんだが、
エスパーのちからを発揮して API を当てて行こうぜ☆?」
「 rectangle はデータじゃなくて、 rectangle を塗りつぶすというメソッドなの?」
「 API のデザインが分からん☆ 異文化に慣れていくしかない☆」
「 じゃあ マウス・クリックしたところの座標を取得しましょう!」
「 左から何ドット目、右から何ドット目に マウスカーソルがあるか 画面に表示してほしいけど、
テキストは出せないんだっけ?」
「 ↑ conrod ではなく、 piston_window を調べればいいのでは……☆?」
Rendering Text in Rust with Piston-Window
「 ↑ なんで .otf に対応してないんだぜ……☆ .ttf はネットに落ちてたものを とりあえず拾ってきたぜ☆」
「 画像と同じサイズの配列を持ちなさい。
クリックしたところに赤、それ以外は透明でも入れておけばいいわ。
確認方法は、そのまま画像として出力すればいいのよ」
「 画像が小さすぎるが、よし、いけてる……☆ 画面のマス目も塗りたいよな☆」
「 JSON ファイルで ライン・ツールのオン、オフを決めればいいのよ。
JSON ファイルを毎秒監視して、更新があったら反映したらいいんじゃない?」
{
"tool": "pen"
}
「 例えば こんな感じかだぜ☆? 手抜きも 突き抜けてるな……☆」
「 イベント・ループと同じ スレッド に ファイル入出力を書くのかだぜ、そんなバカな……☆」
「 ミリ秒とか フレームの取り方も分からん☆
ループ100週に1回とかでいいか……☆」
「 ↑ こんな感じでいけるんじゃないかだぜ☆? やってみようぜ☆?」
「 ↑ 短い方を、長い方で割って 傾きを出せだぜ☆
あとは 長い方に合わせて 短い方の数を出せだぜ☆」
「 うん? なんか以前 ズームとか作ったっけ☆? 計算合わねーッ☆」
「 右下から左上に線を引くと 横幅と縦幅がマイナスになって、Rust の for 文は カウントアップだから エラーで強制終了するんだけど?」
「 Rust言語の for 文は むずかしい書き方が嫌いらしく、カウントアップ専用なんだぜ☆
だから 本来なら 問題ないんだが、エラーになってしまう☆
長い方の辺の長さが 負の数 だったら、 .rev()
を利用して逆順の for 文にしろだぜ☆
そのあと、ループカウンターは -1 を掛けて使えだぜ☆」
「 ↑ しかし この時点でもう プログラムが ごちゃごちゃ している……☆」
<書きかけ>
Crieitは個人で開発中です。
興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!