Pull to refresh
4
0
Настоящее имя@AngReload

Специализация

Send message

Я конечно же совсем не знаю С, но пост напоминает многие статьи по JS типа "Как не сложить число со строкой".

Круть, не замечал что в винде такая штука есть. Но попробовав, так и не смог понять какой фильтр нужно использовать: часть тестовых картинок чуть лучше с фильтром для дейтранопии, часть со вторым — для протанопии, и треть — ни с каким фильтром не удалось разглядеть. Что-то у меня редкое. Хотя скорее всего — обычная дейтераномалия, просто фильтры слишком несовершенные.

На счёт шрифтов, в не понятно зачем делать шрифт жирнее, в фаерфоксе и так текст рендерится более жирным чем в хроме.


Спойлер со сравнением

Скрин из Хрома:
chrome
И Огнелис. Сверху — обычный режим:
text
… и снизу — изменённый, который я бы хотел ещё упомянуть. Тут писал про настройку, которая делает текст более гладким, но и менее резким (хотя разницу, должно быть, трудно заметить).

Не согласен. К коллайдеру!
Треугольник слева уменьшен, а затем увеличен в 2 раза, а справа — тоже самое, но в 1.5 раза.
VS
Мне это и на глаз видно, но давайте замерим PSNR (чем больше тем лучше). Слева psnr = 27.6 против 29.8 справа.

Теперь Википедия-тян совсем взрослая и Роскомнадзор её не заблокирует?
Википедия-тян
Автор у комикса русский - Ремизов, но есть перевод

Обратный отсчёт. Countdown. Комикс. Ремизов

А можете сделать метки времени как тег time с машиночитаемым атрибутом datetime и таймзоной?
Сейчас-то не очень удобно их парсить, а с английской версией вообще ужас-ужас...


javascript
  const datesMap = new Map();
  const megapostTimeEl = document.querySelector('.megapost-head__meta > .list_inline > .list__item');
  (megapostTimeEl ? [megapostTimeEl] : [])
    .concat(Array.from(document.querySelectorAll(`
        .post__time,
        .preview-data__time-published,
        time.comment__date-time_published,
        .tm-post__date,
        .user-message__date-time
      `))).forEach((el) => {
      datesMap.set(el, new HabraTime(el));
    });

  const pageLoadTime = new Date();
  const monthNames = [
    'января', 'февраля', 'марта',
    'апреля', 'мая', 'июня',
    'июля', 'августа', 'сентября',
    'октября', 'ноября', 'декабря',
  ];

  class HabraTime {
    constructor(el, parent) {
      this.el = el;
      this.parent = parent;
      this.attrDatetime = this.constructor.getAttributeDatetime(el);
      this.date = new Date(this.attrDatetime);
    }

    static getAttributeDatetime(el) {
      const re = /((сегодня|вчера)|(\d+)[ .]([а-я]+|\d+)[ .]?(\d+)?) в (\d\d:\d\d)/;
      let [,,
        recently, // eslint-disable-line prefer-const
        day, month, year,
        time, // eslint-disable-line prefer-const
      ] = el.innerHTML.match(re);

      // и местное время
      let moscow;
      if (recently || year === undefined) {
        const offsetMoscow = 3 * 60 * 60 * 1000;
        const yesterdayShift = (recently === 'вчера') ? 24 * 60 * 60 * 1000 : 0;
        const offset = pageLoadTime.getTimezoneOffset() * 60 * 1000;
        const value = (pageLoadTime - yesterdayShift) + offsetMoscow + offset;
        moscow = new Date(value);
      }

      if (recently) {
        day = moscow.getDate();
        month = moscow.getMonth() + 1;
      } else if (month.length !== 2) {
        month = monthNames.indexOf(month) + 1;
      } else {
        month = +month;
      }

      if (day < 10) day = `0${+day}`;
      if (month < 10) month = `0${month}`;
      if (year < 100) year = `20${year}`;
      if (year === undefined) year = moscow.getFullYear();

      return `${year}-${month}-${day}T${time}+03:00`;
    }
  // ...

Это в статике на сферах. На кубиках в падении или если их мышкой таскать — у меня подтормаживает до 0.023s -> 43fps. И, кажется, симуляции недостаточно точные — в демке с неровной землёй один кубик проваливается сквозь сетку.

Мне кажется что сравнимый можно получить построив квадродерево.

Mozilla разрабатывает новый мобильный браузер Fenix

Firefox for Android, Firefox Focus, Firefox Klar, Firefox Lite, Firefox Rocket, теперь ещё и Firefox Fenix — зачем им столько мобильных браузеров?

Оно редактируется. Прокрутите до строчки (под заголовком Internals):


ascii = `$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~<>i!lI;:,"^. `

При наведении левее появятся три точки под которыми скрывается пункт Edit. Впишите:


ascii = `█▓▒░ `

или любой другой набор символов. И нажмите на иконку треугольника справа. Готово.


скриншот

На некоторых числах if(options.hue == 360) options.hue = 0; никогда не выполнится, надо использовать >=.
И это условие должно идти после сложения.
Цвет в любом случае меняется, hue == 361 будет интерпретирован как hue == 1, но всё-таки это ошибка.
Лучше использовать остаток от деления:


options.hue += 1 / options.divisionSpeed;
options.hue %= 360;
С другим набором символов █▓▒░

Гифки на 23 и 8 мегабайт, при том что демки целиком (вместе с логотипом DOOM-a) весят 400 килобайт.


Спрятал под спойлер

Держите на Rust:


Cargo.toml
name = "pixar"
version = "0.1.0"
authors = ["AndrewKensler <xxx@xxx.xx>"]
edition = "2018"

[dependencies]
rand = "*"
png = "*"
indicatif = "*"
num_cpus = "*"

[profile.dev]
opt-level = 3

main.rs
const IS_HABR: bool = false;
const WIDTH: u32 = 960;
const HEIGHT: u32 = 540;
const SAMPLES_POW: u32 = 4;
const BOUNCE_COUNT: u32 = 3;

const HIT_NONE: u8 = 0;
const HIT_LETTER: u8 = 1;
const HIT_WALL: u8 = 2;
const HIT_SUN: u8 = 3;

#[derive(Copy, Clone)]
struct Vec3 {
    x: f64,
    y: f64,
    z: f64,
}

impl Vec3 {
    fn new(x: f64, y: f64, z: f64) -> Vec3 {
        Vec3 { x, y, z }
    }
    fn repeat(v: f64) -> Vec3 {
        Vec3::new(v, v, v)
    }
    fn zeros() -> Vec3 {
        Vec3::repeat(0.)
    }
    #[allow(dead_code)]
    fn rotate_x(self, c: f64) -> Vec3 {
        Vec3::new(
            self.x,
            self.y * c.cos() - self.z * c.sin(),
            self.y * c.sin() + self.z * c.cos(),
        )
    }
    #[allow(dead_code)]
    fn rotate_y(self, c: f64) -> Vec3 {
        Vec3::new(
            self.z * c.sin() + self.x * c.cos(),
            self.y,
            self.z * c.cos() - self.x * c.sin(),
        )
    }
    #[allow(dead_code)]
    fn rotate_z(self, c: f64) -> Vec3 {
        Vec3::new(
            self.x * c.cos() - self.y * c.sin(),
            self.x * c.sin() + self.y * c.cos(),
            self.z,
        )
    }
}

use ::std::ops::{Add, Mul, Not, Rem};

impl Add for Vec3 {
    type Output = Vec3;
    fn add(self, other: Vec3) -> Vec3 {
        Vec3 {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}
impl Add<f64> for Vec3 {
    type Output = Vec3;
    fn add(self, other: f64) -> Vec3 {
        Vec3 {
            x: self.x + other,
            y: self.y + other,
            z: self.z + other,
        }
    }
}
impl Mul for Vec3 {
    type Output = Vec3;
    fn mul(self, other: Vec3) -> Vec3 {
        Vec3 {
            x: self.x * other.x,
            y: self.y * other.y,
            z: self.z * other.z,
        }
    }
}
impl Mul<f64> for Vec3 {
    type Output = Vec3;
    fn mul(self, other: f64) -> Vec3 {
        Vec3 {
            x: self.x * other,
            y: self.y * other,
            z: self.z * other,
        }
    }
}
impl Rem for Vec3 {
    type Output = f64;
    fn rem(self, other: Vec3) -> f64 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }
}
impl Not for Vec3 {
    type Output = Vec3;
    fn not(self) -> Vec3 {
        self * (1. / (self % self).sqrt())
    }
}

// Rectangle CSG equation. Returns minimum signed distance from
// space carved by
// lowerLeft vertex and opposite rectangle vertex upperRight.
fn box_test(position: Vec3, lower_left: Vec3, upper_right: Vec3) -> f64 {
    let lower_left = position + lower_left * -1.;
    let upper_right = upper_right + position * -1.;
    -lower_left
        .x
        .min(lower_left.y)
        .min(lower_left.z)
        .min(upper_right.x)
        .min(upper_right.y)
        .min(upper_right.z)
}

fn min(a: f64, b: f64) -> f64 {
    a.min(b)
}

// Sample the world using Signed Distance Fields.
fn query_database(position: Vec3, hit_type: &mut u8) -> f64 {
    let mut distance = 1_000_000_000.0_f64;
    let mut f = position; // Flattened position (z=0)
    f.z = 0.;
    if IS_HABR {
        let letters = [
            // X
            (57, 79, 65, 95),
            (57, 95, 65, 79),
            // A
            (69, 79, 73, 95),
            (73, 95, 77, 79),
            (71, 87, 75, 87),
            // B (without curves)
            (81, 79, 81, 95),
            (81, 79, 85, 79),
            (81, 87, 85, 87),
            (81, 95, 85, 95),
            // R (without curve)
            (93, 79, 93, 95),
            (93, 87, 97, 87),
            (93, 95, 97, 95),
            (95, 87, 101, 79),
        ];

        for letter in letters.iter() {
            let begin = Vec3::new(letter.0 as f64 - 79., letter.1 as f64 - 79., 0.) * 0.5;
            let e = Vec3::new(letter.2 as f64 - 79., letter.3 as f64 - 79., 0.) * 0.5 + begin * -1.;
            let o = f + (begin + e * (-((begin + f * -1.) % e / (e % e)).min(0.)).min(1.)) * -1.;
            distance = distance.min(o % o); // compare squared distance.
        }
    } else {
        let letters = [
            // 15 two points lines
            "5O5_", "5W9W", "5_9_", // P (without curve)
            "AOEO", "COC_", "A_E_", // I
            "IOQ_", "I_QO", // X
            "UOY_", "Y_]O", "WW[W", // A
            "aOa_", "aWeW", "a_e_", "cWiO", // R (without curve)
        ];

        for letter in letters.iter() {
            let points = letter.as_bytes();
            let begin = Vec3::new(points[0] as f64 - 79., points[1] as f64 - 79., 0.) * 0.5;
            let e = Vec3::new(points[2] as f64 - 79., points[3] as f64 - 79., 0.) * 0.5 + begin * -1.;
            let o = f + (begin + e * (-((begin + f * -1.) % e / (e % e)).min(0.)).min(1.)) * -1.;
            distance = distance.min(o % o); // compare squared distance.
        }
    }
    distance = distance.sqrt(); // Get real distance, not square distance.

    // Two curves (for P and R in PixaR) with hard-coded locations.
    let curves = if IS_HABR {
        vec![Vec3::new(3., 6., 0.), Vec3::new(3., 2., 0.), Vec3::new(9., 6., 0.)]
    } else {
        vec![Vec3::new(-11., 6., 0.), Vec3::new(11., 6., 0.)]
    };
    for curve in curves.iter() {
        let mut o = f + *curve * -1.;
        distance = distance.min(if o.x > 0. {
            ((o % o).sqrt() - 2.).abs()
        } else {
            o.y += if o.y > 0. { -2. } else { 2. };
            (o % o).sqrt()
        });
    }
    distance = (distance.powf(8.) + position.z.powf(8.)).powf(0.125) - 0.5;
    *hit_type = HIT_LETTER;

    let room_dist = min(
        // min(A,B) = Union with Constructive solid geometry
        //-min carves an empty space
        -min(
            // Lower room
            box_test(
                position,
                Vec3::new(-30., -0.5, -30.),
                Vec3::new(30., 18., 30.),
            ),
            // Upper room
            box_test(
                position,
                Vec3::new(-25., 17., -25.),
                Vec3::new(25., 20., 25.),
            ),
        ),
        box_test(
            // Ceiling "planks" spaced 8 units apart.
            Vec3::new(position.x.abs() % 8., position.y, position.z),
            Vec3::new(1.5, 18.5, -25.),
            Vec3::new(6.5, 20., 25.),
        ),
    );
    if room_dist < distance {
        distance = room_dist;
        *hit_type = HIT_WALL;
    };

    let sun = 19.9 - position.y; // Everything above 19.9 is light source.
    if sun < distance {
        distance = sun;
        *hit_type = HIT_SUN;
    }

    return distance;
}

fn ray_marching(origin: Vec3, direction: Vec3, hit_pos: &mut Vec3, hit_norm: &mut Vec3) -> u8 {
    let mut hit_type = HIT_NONE;
    let mut no_hit_count = 0;

    // Signed distance marching
    let mut total_d = 0.;
    while total_d < 100. {
        *hit_pos = origin + direction * total_d;
        let d = query_database(*hit_pos, &mut hit_type); // distance from closest object in world.
        if d < 0.01 || no_hit_count > 99 {
            *hit_norm = !Vec3::new(
                query_database(*hit_pos + Vec3::new(0.01, 0., 0.), &mut no_hit_count) - d,
                query_database(*hit_pos + Vec3::new(0., 0.01, 0.), &mut no_hit_count) - d,
                query_database(*hit_pos + Vec3::new(0., 0., 0.01), &mut no_hit_count) - d,
            );
            return hit_type;
        }
        no_hit_count += 1;
        total_d += d;
    }
    return 0;
}

fn trace(origin: Vec3, direction: Vec3) -> Vec3 {
    let mut origin = origin;
    let mut direction = direction;
    let mut sampled_position = Vec3::zeros();
    let mut normal = Vec3::zeros();
    let mut color = Vec3::zeros();
    let mut attenuation = Vec3::repeat(1.);

    let light_direction = !Vec3::new(0.6, 0.6, 1.0);

    let bounce_count = BOUNCE_COUNT;
    for _ in 0..bounce_count {
        let hit_type = ray_marching(origin, direction, &mut sampled_position, &mut normal);
        if hit_type == HIT_NONE {
            break;
        } // No hit. This is over, return color.
        if hit_type == HIT_LETTER {
            // Specular bounce on a letter. No color acc.
            direction = direction + normal * (normal % direction * -2.);
            origin = sampled_position + direction * 0.1;
            attenuation = attenuation * 0.2; // Attenuation via distance traveled.
        }
        if hit_type == HIT_WALL {
            // Wall hit uses color yellow?
            let incidence = normal % light_direction;
            let p = 6.283185 * random_val();
            let c = random_val();
            let s = (1. - c).sqrt();
            let g = if normal.z < 0. { -1. } else { 1. };
            let u = -1. / (g + normal.z);
            let v = normal.x * normal.y * u;
            direction = Vec3::new(v, g + normal.y * normal.y * u, -normal.y) * p.cos() * s
                + Vec3::new(1. + g * normal.x * normal.x * u, g * v, -g * normal.x) * p.sin() * s
                + normal * c.sqrt();
            origin = sampled_position + direction * 0.1;
            attenuation = attenuation * 0.2;
            if incidence > 0.
                && ray_marching(
                    sampled_position + normal * 0.1,
                    light_direction,
                    &mut sampled_position,
                    &mut normal,
                ) == HIT_SUN
            {
                color = color + attenuation * Vec3::new(500., 400., 100.) * incidence;
            }
        }
        if hit_type == HIT_SUN {
            //
            color = color + attenuation * Vec3::new(50., 80., 100.);
            break; // Sun Color
        }
    }
    return color;
}

fn random_val() -> f64 {
    rand::random()
}

fn get_sampling_points(pow: u32) -> Vec<(f64, f64)> {
    let mut points = vec![];
    let max = 1 << pow;
    for a in 0..max {
        let mut b = 0;
        for i in 0..pow {
            let mask_a = 1 << i;
            let bit = (mask_a & a) != 0;
            if bit {
                let mask_b = 1 << (pow - i - 1);
                b = b | mask_b;
            }
        }
        points.push(((a as f64 + 0.5) / max as f64, (b as f64 + 0.5) / max as f64));
    }
    points
}
use std::time::Instant;
use std::thread;

extern crate indicatif;
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};

fn main() {
    let w = WIDTH as i32;
    let h = HEIGHT as i32;
    let samples_power = SAMPLES_POW;
    let samples_count = 1 << samples_power;

    let now = Instant::now();
    let m = MultiProgress::new();
    let sty = ProgressStyle::default_bar()
        .template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {eta_precise}")
        .progress_chars("=>-");

    let get_promise = move |y0, y1, pb: ProgressBar| -> Vec<u8> {
        let sampling_points = &get_sampling_points(samples_power);
        let position = Vec3::new(-22., 5., 25.);
        let goal = !(Vec3::new(-3., 4., 0.) + position * -1.);

        let left = Vec3::new(goal.z, 0., -goal.x) * (1. / w as f64);
        let up = Vec3::new(
            goal.y * left.z - goal.z * left.y,
            goal.z * left.x - goal.x * left.z,
            goal.x * left.y - goal.y * left.x,
        );

        let mut image_data: Vec<u8> = Vec::with_capacity((w * h * 3) as usize);

        for y in y0..y1 {
            for x in 0..w {
                let x = (w / 2 - x) as f64;
                let y = (h / 2 - y) as f64;
                let mut color = Vec3::zeros();
                for p in sampling_points {
                    let x = x + p.0;
                    let y = y + p.1;
                    color = color + trace(position, !(goal + left * x + up * y));
                }
                color = color * (1. / samples_count as f64) + 14. / 241.;
                let o = color + 1.;
                color = Vec3::new(color.x / o.x, color.y / o.y, color.z / o.z) * 255.;

                image_data.push(color.x.max(0.).min(255.) as u8);
                image_data.push(color.y.max(0.).min(255.) as u8);
                image_data.push(color.z.max(0.).min(255.) as u8);
            }
            pb.inc(1);
        }
        pb.finish_with_message("done");
        image_data
    };

    println!("Rendering...");
    let mut promices = vec![];
    let num_logical_cores = num_cpus::get() as i32;
    for n in 0..num_logical_cores {
        let fragment_size = h / num_logical_cores;
        let y0 = fragment_size * n;
        let y1 = if n == num_logical_cores - 1 {
            h
        } else {
            fragment_size * (n + 1)
        };
        let length = (y1 - y0) as u64;

        let pb = m.add(ProgressBar::new(length));
        pb.set_style(sty.clone());

        let promice = thread::spawn(move || {
            get_promise(y0, y1, pb)
        });

        promices.push(promice);
    }

    m.join_and_clear().unwrap();
    let mut image_data = Vec::new();
    for promice in promices {
        let mut thread_image_data = promice.join().unwrap();
        image_data.append(&mut thread_image_data);
    }

    println!("{} sec", now.elapsed().as_secs());

    let name = format!("{}_{:04}.png", if IS_HABR { "habr" } else { "pixar" }, samples_count);
    let path = std::path::Path::new(&name);
    let file = std::fs::File::create(path).unwrap();
    let ref mut writer_1 = std::io::BufWriter::new(file);

    let mut encoder = png::Encoder::new(writer_1, w as u32, h as u32);
    use png::HasParameters;
    encoder.set(png::ColorType::RGB).set(png::BitDepth::Eight);
    let mut writer = encoder.write_header().unwrap();
    writer.write_image_data(&image_data).unwrap();
}

А я наивно ждал другое слово:
habr

x от 53 до 105 (слева направо)
y от 79 до 95 (снизу вверх)


53, 79, 105, 79, // линия у пола
53, 95, 105, 95, // верх надписи

Сейчас Firefox Beta показывает WebP, в этом месяце выйдет стабильная версия с его поддержкой.

Там же в комментариях написано without curve. Дугу из линий не построить, они дорисовываются вот тут:


// Two curves (for P and R in PixaR) with hard-coded locations.
  Vec curves[] = {Vec(-11, 6), Vec(11, 6)};
  for (int i = 2; i--;) {
    Vec o = f + curves[i] * -1;
    distance = min(distance,
                   o.x > 0 ? fabsf(sqrtf(o % o) - 2)
                           : (o.y += o.y > 0 ? -2 : 2, sqrtf(o % o))
               );
  }

Я ещё помню «Эксперимент длиной в год», оказывается уже четыре года пролетело. С наступившим!
По графикам — извините, ничего не понял. Первые два, шкала до 85 — что это? Следующие, что значат года через дробь, от чего проценты, чем отличаются первая пара от второй?

Information

Rating
Does not participate
Registered
Activity