construct2_3d ›

construct2

//
//  construct2.rs
//
//  Copyright (c) 2001 Fredrik Olofsson Musikproduktion. All rights reserved.
//
//  2001 original code in java
//  010502 max patch (rev.011004)
//  040920 ported to processing
//  060227 3d version for processing
//  071201 ported to sc (RedConstruct)
//  200326 ported to p5js
//  210517 ported to nannou

// ---------------------------------------------------------------------------------------

use nannou::prelude::*;

const MOV_X: u8 = 95;
const MOV_Y: u8 = 95;

struct Model {
    c: Rgb8,
    step_x: i32,
    step_y: i32,
    x: i32,
    y: i32,
    dx: i32,
    dy: i32,
    v: u8,  //variant
    m: u8,  //mapping
    col: i32,
    row: i32,
    max_x: i32,
    max_y: i32,
    reset: u8,
}

fn main() {
    nannou::app(model).update(update).run();
}

fn model(app: &App) -> Model {
    app.new_window()
    .event(event)
    .size(640, 480)
    .title("Construct2")
    .view(view)
    .build()
    .unwrap();
    let c = rgb(255, 55, 66);
    let step_x = 1;
    let step_y = 1;
    let x = 10;
    let y = 10;
    let dx = 1;
    let dy = 1;
    let v = 1;
    let m = 1;
    let col = 4;
    let row = 3;
    let max_x = app.window_rect().w() as i32;
    let max_y = app.window_rect().h() as i32;
    let reset = 1;
    Model {
        c,
        step_x,
        step_y,
        x,
        y,
        dx,
        dy,
        v,
        m,
        col,
        row,
        max_x,
        max_y,
        reset,
    }
}

fn event(_app: &App, model: &mut Model, event: WindowEvent) {
    match event {
        KeyPressed(key) => {
            if let Key::Space = key {
                model.reset = 1;
            }
        },
        MousePressed(_button) => {
            model.reset = 1;
        },
        _ => {},
    }
}

fn update(_app: &App, model: &mut Model, _update: Update) {
    if random_range(0, 1881) == 0 {
        model.reset = 1;
    }

    if model.reset == 1 {
        nytt(model); // nya värden
        model.reset = 2;
    } else if model.reset == 2 {
        model.reset = 0;
    }

    model.x += model.dx * model.step_x; // flytta position x
    if model.x < 1 { // om vänster kant
        model.dx = random_range(0, 2); // vänd eller stå still i x-led
    } else if model.x > model.max_x / model.col { // om höger kant
        model.dx = 0 - random_range(0, 2); // vänd eller stå still i x-led
    }

    model.y += model.dy * model.step_y; // flytta position y
    if model.y < 1 { // om övre kanten
        model.dy = random_range(0, 2) // vänd eller stå still i y-led
    } else if model.y > model.max_y / model.row { // om nedre kanten
        model.dy = 0 - random_range(0, 2) // vänd eller stå still i y-led
    }

    match model.v {
        1 => variant1(model),
        2 => variant2(model),
        3 => variant3(model),
        4 => variant4(model),
        5 => variant5(model),
        6 => variant6(model),
        _ => (),
    }
}

// ---------------------------------------------------------------------------------------
fn variant1(model: &mut Model) { // 1. slumpa riktningar individuellt
    if random_range(0, 100) >= MOV_X {
        slumpa_riktning_x(model);
    }
    if random_range(0, 100) >= MOV_Y {
        slumpa_riktning_y(model);
    }
}
fn variant2(model: &mut Model) { // 2. slumpa alltid riktningar tillsammans
    slumpa_riktning_xy(model);
}
fn variant3(model: &mut Model) { // 3. slumpa riktningar individuellt
    if random_range(0, 100) >= MOV_X {
        if model.dx == 0 && model.x >= 1 { // dra åt vänster
            model.dx = -1;
        } else {
            model.dx = 0;
        }
    }
    if random_range(0, 100) >= MOV_Y {
        if model.dy == 0 && model.y >= 1 { // dra uppåt
            model.dy = -1;
        } else {
            model.dy = 0;
        }
    }
}
fn variant4(model: &mut Model) { // 4. slumpa riktningar individuellt
    if random_range(0, 100) >= MOV_X {
        if model.dx == 0 && model.x >= 1 { // dra åt vänster
            model.dx = -1;
        } else {
            model.dx = 0;
        }
    }
    if random_range(0, 100) >= MOV_Y {
        if model.dy == 0 && model.y <= model.max_y / model.row { // dra nedåt
            model.dy = 1;
        } else {
            model.dy = 0;
        }
    }
}
fn variant5(model: &mut Model) { // 5. slumpa riktningar individuellt
    if random_range(0, 100) >= MOV_X {
        if model.dx == 0 && model.x <= model.max_x / model.col { // dra åt höger
            model.dx = 1;
        } else {
            model.dx = 0;
        }
    }
    if random_range(0, 100) >= MOV_Y {
        if model.dy == 0 && model.y >= 1 { // dra uppåt
            model.dy = -1;
        } else {
            model.dy = 0;
        }
    }
}
fn variant6(model: &mut Model) { // 6. slumpa riktningar individuellt
    if random_range(0, 100) >= MOV_X {
        if model.dx == 0 && model.x <= model.max_x / model.col { // dra åt höger
            model.dx = 1;
        } else {
            model.dx = 0;
        }
    }
    if random_range(0, 100) >= MOV_Y {
        if model.dy == 0 && model.y <= model.max_y / model.row { // dra nedåt
            model.dy = 1;
        } else {
            model.dy = 0;
        }
    }
}

// ---------------------------------------------------------------------------------------
fn nytt(model: &mut Model) {
    model.v = random_range(0, 6) + 1;
    model.m = random_range(0, 16) + 1;
    model.col = random_range(0, 12) + 1;
    model.row = random_range(0, 7) + 1;
    model.step_x = 1;
    // model.step_x = random_range(0, 2) + 1;
    model.step_y = 1;
    // model.step_y = random_range(0, 2) + 1;
    slumpa_riktning_xy(model);
    model.c.red = random_range(0, 255);
}

fn slumpa_riktning_x(model: &mut Model) {
    model.dx = random_range(0, 2);
}
fn slumpa_riktning_y(model: &mut Model) {
    model.dy = random_range(0, 2);
}
fn slumpa_riktning_xy(model: &mut Model) {
    while model.dx == 0 && model.dy == 0 { // kolla att inte båda riktningar blir 0
        model.dx = random_range(0, 2);
        model.dy = random_range(0, 2);
    }
}

// ---------------------------------------------------------------------------------------
fn draw_fo(model: &Model, draw: &Draw) {
    for i in 0..model.col {
        let i_col = (model.max_x / model.col) * i;
        for j in 0..model.row {
            let j_row = (model.max_y / model.row) * j;
            let point = match model.m { // kolla mapping
                1 => mapping1(model, i, j, i_col, j_row),
                2 => mapping2(model, i, j, i_col, j_row),
                3 => mapping3(model, i, j, i_col, j_row),
                4 => mapping4(model, i, j, i_col, j_row),
                5 => mapping5(model, i, j, i_col, j_row),
                6 => mapping6(model, i, j, i_col, j_row),
                7 => mapping7(model, i, j, i_col, j_row),
                8 => mapping8(model, i, j, i_col, j_row),
                9 => mapping9(model, i, j, i_col, j_row),
                10 => mapping10(model, i, j, i_col, j_row),
                11 => mapping11(model, i, j, i_col, j_row),
                12 => mapping12(model, i, j, i_col, j_row),
                13 => mapping13(model, i, j, i_col, j_row),
                14 => mapping14(model, i, j, i_col, j_row),
                15 => mapping15(model, i, j, i_col, j_row),
                16 => mapping16(model, i, j, i_col, j_row),
                _ => pt2(0, 0),
            };
            draw.rect().x_y(point.x as f32, point.y as f32).w_h(1.0, 1.0).color(model.c);
        }
    }
}

fn view(app: &App, model: &Model, frame: Frame) {
    let win = app.main_window().rect();
    let draw = app.draw().x_y(win.w() * -0.5, win.h() * -0.5);
    if model.reset > 0 {
        frame.clear(WHITE); // rensa skärmen
    }
    draw_fo(model, &draw);
    draw.to_frame(app, &frame).unwrap();
}

// ---------------------------------------------------------------------------------------
fn mapping1(model: &Model, _i: i32, _j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // no flip
    vec2(model.x + i_col, model.y + j_row)
}
fn mapping2(model: &Model, _i: i32, _j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip all x
    vec2(mirror_x(model) + i_col, model.y + j_row)
}
fn mapping3(model: &Model, _i: i32, _j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip all y
    vec2(model.x + i_col, mirror_y(model) + j_row)
}
fn mapping4(model: &Model, _i: i32, _j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip all xy
    vec2(mirror_x(model) + i_col, mirror_y(model) + j_row)
}
// --
fn mapping5(model: &Model, i: i32, _j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip odd col x
    if i % 2 == 1 {
        vec2(mirror_x(model) + i_col, model.y + j_row)
    } else {
        vec2(model.x + i_col, model.y + j_row)
    }
}
fn mapping6(model: &Model, i: i32, _j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip odd col y
    if i % 2 == 1 {
        vec2(model.x + i_col, mirror_y(model) + j_row)
    } else {
        vec2(model.x + i_col, model.y + j_row)
    }
}
fn mapping7(model: &Model, i: i32, _j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip odd col xy
    if i % 2 == 1 {
        vec2(mirror_x(model) + i_col, mirror_y(model) + j_row)
    } else {
        vec2(model.x + i_col, model.y + j_row)
    }
}
// --
fn mapping8(model: &Model, _i: i32, j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip odd row x
    if j % 2 == 1 {
        vec2(mirror_x(model) + i_col, model.y + j_row)
    } else {
        vec2(model.x + i_col, model.y + j_row)
    }
}
fn mapping9(model: &Model, _i: i32, j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip odd row y
    if j % 2 == 1 {
        vec2(model.x + i_col, mirror_y(model) + j_row)
    } else {
        vec2(model.x + i_col, model.y + j_row)
    }
}
fn mapping10(model: &Model, _i: i32, j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip odd row xy
    if j % 2 == 1 {
        vec2(mirror_x(model) + i_col, mirror_y(model) + j_row)
    } else {
        vec2(model.x + i_col, model.y + j_row)
    }
}
// --
fn mapping11(model: &Model, i: i32, j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip odd col & even row x, flip even col & odd row x
    if i % 2 == 1 && j % 2 == 0 {
        vec2(mirror_x(model) + i_col, model.y + j_row)
    } else if i % 2 == 0 && j % 2 == 1 {
        vec2(mirror_x(model) + i_col, model.y + j_row)
    } else {
        vec2(model.x + i_col, model.y + j_row)
    }
}
fn mapping12(model: &Model, i: i32, j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip odd col & even row y, flip even col & odd row y
    if i % 2 == 1 && j % 2 == 0 {
        vec2(model.x + i_col, mirror_y(model) + j_row)
    } else if i % 2 == 0 && j % 2 == 1 {
        vec2(model.x + i_col, mirror_y(model) + j_row)
    } else {
        vec2(model.x + i_col, model.y + j_row)
    }
}
fn mapping13(model: &Model, i: i32, j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip odd col & even row xy, flip even col & odd row xy
    if i % 2 == 1 && j % 2 == 0 {
        vec2(mirror_x(model) + i_col, mirror_y(model) + j_row)
    } else if i % 2 == 0 && j % 2 == 1 {
        vec2(mirror_x(model) + i_col, mirror_y(model) + j_row)
    } else {
        vec2(model.x + i_col, model.y + j_row)
    }
}
// --
fn mapping14(model: &Model, i: i32, j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip even col & even row x, flip odd col & odd row x
    if i % 2 == 0 && j % 2 == 0 {
        vec2(mirror_x(model) + i_col, model.y + j_row)
    } else if i % 2 == 1 && j % 2 == 1 {
        vec2(mirror_x(model) + i_col, model.y + j_row)
    } else {
        vec2(model.x + i_col, model.y + j_row)
    }
}
fn mapping15(model: &Model, i: i32, j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip even col & even row y, flip odd col & odd row y
    if i % 2 == 0 && j % 2 == 0 {
        vec2(model.x + i_col, mirror_y(model) + j_row)
    } else if i % 2 == 1 && j % 2 == 1 {
        vec2(model.x + i_col, mirror_y(model) + j_row)
    } else {
        vec2(model.x + i_col, model.y + j_row)
    }
}
fn mapping16(model: &Model, i: i32, j: i32, i_col: i32, j_row: i32) -> Vector2<i32> { // flip even col & even row xy, flip odd col & odd row xy
    if i % 2 == 0 && j % 2 == 0 {
        vec2(mirror_x(model) + i_col, mirror_y(model) + j_row)
    } else if i % 2 == 1 && j % 2 == 1 {
        vec2(mirror_x(model) + i_col, mirror_y(model) + j_row)
    } else {
        vec2(model.x + i_col, model.y + j_row)
    }
}

// ---------------------------------------------------------------------------------------
fn mirror_x(model: &Model) -> i32 {
    model.max_x / model.col - model.x
}
fn mirror_y(model: &Model) -> i32 {
    model.max_y / model.row - model.y
}