2020/02/19

Rust+SDL2でカラーチェック

色を見ながら調整する

RustとSDL2で色を見ながら調整し、最終的にその色のRGBの値とカラーコードを表示するというシンプルなアプリケーションを作成してみました。ソースコードはGitHubに置いていますが、以下のようになっています。

use sdl2;
use sdl2::video::Window;
use sdl2::render::Canvas;
use sdl2::event::Event;
use sdl2::pixels::Color;
use sdl2::keyboard::Keycode;
use std::error::Error;

const TITLE: &'static str = "Color checker";
const WINDOW_WIDTH: u32 = 300;
const WINDOW_HEIGHT: u32 = 300;

struct App {
    canvas: Canvas<Window>,
    event: sdl2::EventPump,
}

impl App {
    fn init() -> Result<Self, String> {
        let sdl_ctx = sdl2::init()?;
        let video_subsys = sdl_ctx.video()?;
        
        let win = video_subsys.window(TITLE, WINDOW_WIDTH, WINDOW_HEIGHT)
            .position_centered()
            .build()
            .map_err(|e| e.to_string())?;
        
        let cvs = win.into_canvas()
            .accelerated()
            .build()
            .map_err(|e| e.to_string())?;
        
        let event_pump = sdl_ctx.event_pump()?;

        Ok(App {
            canvas: cvs,
            event: event_pump,
        })
    }
    fn run_loop(&mut self) {
        let mut color = Color::RGB(0, 0, 0);

        'running: loop {
            self.canvas.set_draw_color(color);
            self.canvas.clear();
            self.canvas.present();
            
            for ev in self.event.poll_iter() {
                match ev {
                    Event::Quit { .. } => break 'running,
                    Event::KeyDown { keycode: Some(k), .. } => {
                        match k {
                            Keycode::Escape => break 'running,
                            Keycode::R => {
                                if color.r < 255 {
                                    color.r += 1;
                                } else {
                                    continue;
                                }
                            },
                            Keycode::G => {
                                if color.g < 255 {
                                    color.g += 1;
                                } else {
                                    continue;
                                }
                            },
                            Keycode::B => {
                                if color.b < 255 {
                                    color.b += 1;
                                } else {
                                    continue;
                                }
                            },
                            Keycode::E => {
                                if color.r > 0 {
                                    color.r -= 1;
                                } else {
                                    continue;
                                }
                            },
                            Keycode::F => {
                                if color.g > 0 {
                                    color.g -= 1;
                                } else {
                                    continue;
                                }
                            },
                            Keycode::V => {
                                if color.b > 0 {
                                    color.b -= 1;
                                } else {
                                    continue;
                                }
                            },
                            _ => {},
                        }
                    },
                    Event::KeyUp { keycode: Some(k), .. } => {
                        match k {
                            Keycode::Escape => break 'running,
                            _ => {},
                        }
                    },
                    _ => {},
                }
            }
        }
        println!("R: {} G: {} B: {}", color.r, color.g, color.b);
        println!("COLOR_CODE: #{:02X}{:02X}{:02X}", color.r, color.g, color.b);
    }
}

fn main() -> Result<(), Box<dyn Error>>{
    let mut app = App::init()?;
    app.run_loop();
    Ok(())
}
結局のところ前回までのSDL2の改造版みたいなものですが、今回はなるべくmain関数から分離することを心がけてみました。
sdl2::pixels::Colorは以下のような構造体になっています。

pub struct Color {
    pub r: u8,
    pub g: u8,
    pub b: u8,
    pub a: u8
}
rはRed、gはGreen、bはBlue、aはAlpha(透明度)となっていて、今回透明度は要らないのでRGBを使いました。どの属性もパブリックなものなのでアクセス可。HTML/CSSで使う場合、16進数のカラーコードを使うことが多いので、以下のようにして、それも表示できるようにしました。

println!("COLOR_CODE: #{:02X}{:02X}{:02X}", color.r, color.g, color.b);
大文字のXを指定することで、大文字の16進数になります。しかし、数値が一桁の場合、空白になってしまうので、02としてゼロパディング2桁にし、0なら00、1なら01と表示できるようにしました。

余談:SDL2の勉強のせいで……

前回もちらっとお話したのですが、SDL2を勉強していてゲームの凄さに気づいてしまったおじさんは、ついにゲームを始めてしまいました。敵が出てくるとかは対処できないので、のんびりとしたものがいい。ということで、minetestというマインクラフトのクローンのゲームを始めました。luaで書かれているようです。以下の画像はおじさんが岩山を切り拓き、ようやく完成したマイホームです。羊がなかなかいなくて、ずっと寝ることなく過酷な労働をしていました。イノシシがいたので、牡丹鍋なんてどうよ?と思った所、オッコトヌシ様級に強くて他界しました。気づけば全く知らない世界に…

なんだろう?すごく癒やされます。スローライフとでも言うのだろうか?マインクラフトが人気な理由がすごく分かってしまいました。