Comments 47
Очень круто!
Круто - не то слово. Лучшая статья на Хабре!)
Во время чтения чувствовал себя орущим БП с графиком удивления из AAAAAAAAA!
Да — фактически, я сначала в реальности разрезал ленты на куски бокорезами, приклеил их, соединил некоторые между собой проводами, а затем на программном уровне снова разделил обратно. Так надо.
«Сначала сами создадим себе проблемы, а потом будем их героически преозмогать», да.
Да)
Ну дык это... «Час планирования экономит неделю работы». Впрочем, «цель оправдывает средства, если применение этих средств является целью».
На самом деле это не на ровном месте всё.
Контроллер — бутылочное горлышко в плане количества лент, 36 штук в него не воткнуть параллельно. И чтобы это горлышко преодолеть я и группировал ленты. А на более высоком уровне абстракции, где мы управляем лентами, это объединение уже наоборот, не нужно. Поэтому мы от него избавляемся.
Уважуха. Вы в одиночку с нуля сделали огромный проект и довели его до финала.
Это... Гениально! Старание, упорство, любопытство! Уффф... Плюс, оформление каждой из статей... Ещё один уфф! Огромное спасибо!
Пойду в проститутки.
Хабр торт. Безумный респект, читаю серию с первой статьи.

О, индусский код, привет! Давненько не виделись!
Впечатляюще. Я бы что-то подобное хотел но только с одним режимом и желательно платформонезависимое которое бы работало чисто внутри себя, не взаимодействуя с ОС.
Ну, это гораздо проще (если не делать анализ экрана). Просто запихиваем нужные рисунки в контроллер и всё. Если нужен «HDR» и всякие плавности — можно либо взять контроллер с поддержкой плавающей запятой, либо запилить fxdlong/fxdint на него (числа с фиксированной запятой).
Единственное — ленты сами не погаснут, если перестать передавать на них значения. Надо именно на них нули подать. Для этого какой‑нибудь пин контроллера замыкаем с +5В USB компа и пишем в контроллер, что если напряжение на входе пропало, плавно погасить подсветку. Например, на каждый кадр делаем битовый сдвиг >>. Тогда она +‑ быстро и плавно погаснет + выкрутит одновременно с этим гамму, и получится необычный эффект.
Я долго не мог понять, почему у меня сайт никак не хочет грузиться. В конце когда он все-таки загрузился, решил проверить одну вещь.

Ой
Очень круто! Респект таким как автор!
[опять_пришел_этот_лиспер_и_брюзжит]
Такой подход, с модификацией классов, уже много лет как реализован в объектной системе Common Lisp CLOS. Там можно на ходу, в уже исполняемой программе, поменять определение класса и все объекты автоматически перестроятся. Удаленные поля исчезнут, новые появятся и будут проинициализированы как надо. Для сложных случаев пишутся специальные методы, которые автоматически вызываются, если класс был обновлен, там можно вставить логику любой сложности, которая обновит поля. Всё же, известная шутка про то, что любая сложная программа содержит в себе неполную и багованную версию лиспа, не совсем шутка))
[/опять_пришел_этот_лиспер_и_брюзжит]
Спасибо!
По CLOS — очень интересно. Я так понял, там и наследование есть, и даже некое подобие метапрограммирования? Но я не увидел: есть ли там фишка, чтобы значения полей отражались в коде?
Наследование есть, разумеется, даже множественное. Метапрограммирование это второе имя лиспа) Про значения полей в коде не очень понятно, но, ничто не мешает сгенерировать на ходу исходник нужной функции с вшитыми нужными значениями (знаменитый синтаксис лиспа со скобочками позволяет естественно работать с кодом, как с данными), прямо на ходу же ее скомпилировать в машинный код и подставить в нужное место. Так же точно можно обновить методы и вообще любые части кода.
Сколько лет это заняло?
хабр вернулся! статья лучшая!
одна похожая оптимизация была в движке Quake :D огонь вобще <3<3<3
Спасибо!)
Да, там был быстрый обратный квадратный корень
//Не путать с C# - в этом C++
//тип long имеет размер 32 бита
//то есть long здесь это int
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the fuck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y;
}
Его там юзали для нормализации вектора (т. е. при сохранении направления делаем длину равной 1) при расчёте освещения. Всё это было нужно, чтобы сглаживать переходы между полигонами и делать их малое количество менее заметным.

ЧТО Вы такое?))) Выглядит, как идеальное сочетание фантазии, интеллекта и возможностей.
Константа 1072632447 взята из https://nic.schraudolph.org/pubs/Schraudolph99.pdf. Там есть и весь нужный матан, чтоб подтьюнить алгоритм.
Отличная статья!
Самое грандиозное - за три года не забросить и заставить ЭТО работать!
Почему в Vist через поля, а не через массив заданной длины?
public class Vist128<T>
{
private readonly T[] _static = new T[128];
private List<T> _dynamic = default!
private int _index = -1;
public T this[int index]
{
get
{
if(index < 128) // и еще чутка проверок, но для примера неважно
{
return _static[index];
}
return _dynamic[index - 128];
}
}
}
Типа того, и писать в лист по выходу за пределы статичного массива. И предсказание перехода будет быстрее при переборе полей и код сильно сократится.
private readonly T[] _static = new T[128];
Так массив выделится в куче — а весь сыр‑бор как раз чтобы избегать этого.
Но если Vist это класс, тогда его поля будут тоже лежать в куче, независимо от своего типа. На стек может падать только в случае если Vist структура. Этот момент не нашел в описании, потому и стало интересно в чем выгода так определять поля.
Сам проект не планируете выложить на гитхаб? Было бы интересно посмотреть идеи.
Крутая статья!
Хотел тоже недавно начать проект со светодиодными лентами. Только не для домашнего, а для клуба, чтобы музыканта со сцены по MIDI мог управлять светодиодной подсветкой всего клуба (внешней и внутренней).
Но как то после прочтения статьи - пока перехотелось :D
@VBDUnit есть вопрос по поводу снятия "скриншота" экрана. Для одного проетка я никак не могу решить задачу получения всего изображения, которое видит пользователь. Суть в том, что некоторые оверлеи не видны на скринах, как бы я не старался. Только через захват всего рабочего стола и только через NVIDIA Shadowplay.
Возможно, что ваш способ c DirectX OutputDuplication может сработать, но я не уверен. Есть предположение, что 5 минут беседы с вами может сэкономить месяц поисков :D
Хотел тоже недавно начать проект со светодиодными лентами. Только не для домашнего, а для клуба, чтобы музыканта со сцены по MIDI мог управлять светодиодной подсветкой всего клуба (внешней и внутренней).
Интересная штука. Можно даже разделить, чтобы цветовыми сочетаниями управлял человек, а динамика и ритм брались из музыки после некоторых обработок.
@VBDUnit есть вопрос по поводу снятия "скриншота" экрана. Для одного проетка я никак не могу решить задачу получения всего изображения, которое видит пользователь. Суть в том, что некоторые оверлеи не видны на скринах, как бы я не старался. Только через захват всего рабочего стола и только через NVIDIA Shadowplay.
Если ShadowPlay работает, то и OutputDuplication действительно может сработать, но не факт. Иногда он капризничает, хотя с играми всё ок.
Есть предположение, что 5 минут беседы с вами может сэкономить месяц поисков
Предлагаю в личке или тг :)
Зажигаем миллиард цветов миллионом строк