Help us understand the problem. What is going on with this article?

プログラムでシダを描画する

More than 5 years have passed since last update.

 やっはろー。これは、Rust Advent Calendar 2014 の 7日目の記事です。Rust から OpenGL を叩いてみたかったので、シダを描くことにしました。

 元ネタです。

プログラムでシダを描画する - 強火で進め

「プログラムでシダを描画する」一覧 - Qiita

// rustc 0.13.0-nightly (d9c7c00b9 2014-12-04 21:33:07 +0000)

extern crate gl;
extern crate glfw;

use std::{mem, ptr, rand};
use gl::types::{GLboolean, GLfloat, GLsizeiptr};
use glfw::Context;

const WIDTH: uint = 512;
const HEIGHT: uint = 512;

static VERTEX_SOURCE: &'static str = "
  #version 150

  in vec2 position;
  out vec2 texcoord;

  void main() {
    texcoord = (vec2(position.x, -1.0 * position.y) + 1.0) / 2.0;
    gl_Position = vec4(position, 0.0, 1.0);
  }";

static FRAGMENT_SOURCE: &'static str = "
  #version 150

  uniform sampler2D tex;
  in vec2 texcoord;
  out vec4 color;

  void main() {
    if (0 < texture(tex, texcoord).r) {
      color = vec4(0.125, 0.502, 0.125, 1.0);
    } else {
      color = vec4(0.0);
    }
  }";

fn main() {
  let image = {
    static mut buffer: [u8, ..WIDTH * HEIGHT] = [0, ..WIDTH * HEIGHT];

    fn fern(n: uint, x: f64, y: f64) {
      fn w1x(x: f64, y: f64) -> f64 { 0.836 * x + 0.044 * y }
      fn w1y(x: f64, y: f64) -> f64 { -0.044 * x + 0.836 * y + 0.169 }
      fn w2x(x: f64, y: f64) -> f64 { -0.141 * x + 0.302 * y }
      fn w2y(x: f64, y: f64) -> f64 { 0.302 * x + 0.141 * y + 0.127 }
      fn w3x(x: f64, y: f64) -> f64 { 0.141 * x - 0.302 * y }
      fn w3y(x: f64, y: f64) -> f64 { 0.302 * x + 0.141 * y + 0.169 }
      fn w4x(_: f64, _: f64) -> f64 { 0.0 }
      fn w4y(_: f64, y: f64) -> f64 { 0.175337 * y }

      if 0 < n {
        fern(n - 1, w1x(x, y), w1y(x, y));
        if rand::random::<f64>() < 0.3 { fern(n - 1, w2x(x, y), w2y(x, y)); } 
        if rand::random::<f64>() < 0.3 { fern(n - 1, w3x(x, y), w3y(x, y)); } 
        if rand::random::<f64>() < 0.3 { fern(n - 1, w4x(x, y), w4y(x, y)); } 
      } else {
        let x = (x * WIDTH as f64 + WIDTH as f64 * 0.5) as uint;
        let y = (HEIGHT as f64 - y * HEIGHT as f64) as uint;
        unsafe { buffer[x + y * HEIGHT] = 1; }
      }
    }

    fern(20, 0.0, 0.0);
    unsafe { buffer.to_vec() }
  };

  unsafe {
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
    glfw.window_hint(glfw::WindowHint::ContextVersion(3, 2));
    glfw.window_hint(glfw::WindowHint::OpenglForwardCompat(true));
    glfw.window_hint(glfw::WindowHint::OpenglProfile(glfw::OpenGlProfileHint::Core));

    let (window, _) =
      glfw.create_window(WIDTH as u32, HEIGHT as u32, "fern", glfw::WindowMode::Windowed).unwrap();
    window.make_current();
    gl::load_with(|s| window.get_proc_address(s));

    let program = gl::CreateProgram();
    for &(type_, source) in [(gl::VERTEX_SHADER, VERTEX_SOURCE),
                             (gl::FRAGMENT_SHADER, FRAGMENT_SOURCE)].iter() {
      let shader = gl::CreateShader(type_);
      source.with_c_str(|source| gl::ShaderSource(shader, 1, &source, ptr::null()));
      gl::CompileShader(shader);
      gl::AttachShader(program, shader);
      gl::DeleteShader(shader);
    }
    gl::LinkProgram(program);
    gl::UseProgram(program);
    "color".with_c_str(|p| gl::BindFragDataLocation(program, 0, p));
    "tex".with_c_str(|p| gl::Uniform1i(gl::GetUniformLocation(program, p), 0));
    gl::UseProgram(0);

    let mut array = 0;
    gl::GenVertexArrays(1, &mut array);
    gl::BindVertexArray(array);

    let position = [-1.0f32, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0];
    let mut buffer = 0;
    gl::GenBuffers(1, &mut buffer);
    gl::BindBuffer(gl::ARRAY_BUFFER, buffer);
    gl::BufferData(gl::ARRAY_BUFFER,
                   (position.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
                   mem::transmute(position.as_ptr()),
                   gl::STATIC_DRAW);
    "position".with_c_str(|p| {
      let location = gl::GetAttribLocation(program, p) as u32;
      gl::EnableVertexAttribArray(location);
      gl::VertexAttribPointer(location, 2, gl::FLOAT, gl::FALSE as GLboolean, 0, ptr::null());
    });
    gl::BindBuffer(gl::ARRAY_BUFFER, 0);
    gl::BindVertexArray(0);

    let mut texture = 0;
    gl::GenTextures(1, &mut texture);
    gl::BindTexture(gl::TEXTURE_2D, texture);
    gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
    gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
    gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGB as i32,
                   WIDTH as i32, HEIGHT as i32,
                   0, gl::RED, gl::UNSIGNED_BYTE, mem::transmute(image.as_ptr()));
    gl::BindTexture(gl::TEXTURE_2D, 0);

    gl::ClearColor(1.0, 1.0, 1.0, 1.0);
    gl::Enable(gl::BLEND);
    gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);

    while !window.should_close() {
      glfw.poll_events();

      gl::Clear(gl::COLOR_BUFFER_BIT);

      gl::UseProgram(program);
      gl::BindTexture(gl::TEXTURE_2D, texture);
      gl::BindVertexArray(array);

      gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);

      gl::BindVertexArray(0);
      gl::BindTexture(gl::TEXTURE_2D, 0);
      gl::UseProgram(0);

      window.swap_buffers();
    }

    gl::DeleteTextures(1, &texture);
    gl::DeleteBuffers(1, &buffer);
    gl::DeleteVertexArrays(1, &array);
    gl::DeleteProgram(program);
  }
}

シダ

楽しい!₍₍ (ง╹◡╹)ว ⁾⁾

床井研究室

wgld.org

bjz/gl-rs - GitHub

bjz/glfw-rs - GitHub

woxtu
世界の上にタンポポをのせる仕事をしています。
qiitadon
Qiitadon(β)から生まれた Qiita ユーザー・コミュニティです。
https://qiitadon.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした