?

Log in

No account? Create an account
nyaload

Журнал Пушыстого

Журнал Пушыстого

Entries by tag: release

Оптимизация размера графики в казуалках
nyaload
_winnie
В казуалках есть одна штука, в которой есть месту техническому теку - это пайплайн, хорошо сжимающий графику. Кто-то считает что необоснованно "пользователю всё равно сколько скачать, 10 мегабайт или 100, он не разбирается", кто-то считает что важно "+10 % к размеру - минус 1% пользователей", ну и видел даму которая не скачивает игры с большим размером "потому что долго ждать".

В mahjongg artifacts встала задача засунуть в небольшой объём много графики - 50 бэков и комиксов 1024x768, плюс всё остальное (музыку, графику, exe).

Были примененен "атласинг", когда мелкие картинки кладутся в одну текстуру что бы не тратить место на заголовки. Кстати, шрифты очень хорошо паковались, тем же алгоритмом упаковки - Read more...Collapse )
Ну, атласинг - это типично.

Ещё один трюк: rgb-канал - жмется в jpg, а альфа канал - в 64 отенках серого png. Для rgb-канала применяется особый трюк, который продолжает rgb-канал в область прозрачности, таким образом сжатие в jpg не портит резкие границы (границы в rgb размываются, и остаются только в альфа-канале):
Read more...Collapse )

И ещё один ультимейт-трюк: в комиксах при выставлении максимального jpeg-сжатия (0% в фотошопе) комикс выглядит в 80% части нормально. Но в некоторых важных местах для человеческого зрения - глаза, губы, пальцы, сюжетные элементы - ужасно. jpeg-изображение состоит из блоков 16x16. Не вопрос, пишем тулзу в которой указываем какие квадратики 16x16 надо сжимать хорошо, и в игровом коде рисуем эти квадратики-заплатки поверх плохого Jpeg:
Как выглядят патчи:
Read more...Collapse )

Редактор:
Read more...Collapse )

см. так же про то, как удобней сделать интерфейс рисования спрайтов

Текст: выделение по словам, по строкам.
nyaload
_winnie
Товарищи!
Я думал что это знают все люди, много работающие с кодом и конфигами! Но я был не прав! Итак:

В любых нормальных Windows-UI редакторах (включая браузеры):

1) Ctrl+Del или Ctrl+Backspace - удалить слово. Shift+Ctrl+Стрелки - и можно выделять по словам.

2) Home, затем Shift + (стрелка вниз)*N - выделить текущую строку (N строк).

3) Ctrl+Home, Ctrl+End - в начало документа, в конец документа.

Старые студенческие работы.
nyaload
_winnie
У меня есть какие-то старые студенческие поделки про компьютерную графику, выкладываю что бы не потерялось и показать :)

Например, Часы Зла. Можно вращать, можно правой кнопкой мыши щелкать по глазам и бубену.
Скачать (1 мегабайт).

Ещё всякое такое можно посмотреть на http://dobrokot.ru/opengl-demos/

Робоконтроль
nyaload
_winnie
Я себе сделал скрипт, который поверх стандартного c:\windows\system32\drivers\etc\hosts копирует мой, где забанено всякое (жежешечка, вконтактик, твитор и тп тд).

Скрипт доступен из меню Пуск, там где же где и браузер-почта сверху.

А обратного скрипта не сделал, всегда руками разбаниваю :)

В результате я могу всё развлекательное забанить одним кликом мыши, а обратно - где-то в течении минуты.

Помогает, уже больше года.

Read more...Collapse )

потому что в кузнице не было гвоздя
nyaload
_winnie
Не было гвоздя — подкова пропала.
Не было подковы — лошадь захромала.
Лошадь захромала — командир убит.
Конница разбита — армия бежит.
Враг ступает в город, пленных не щадя,
От того, что в кузнице не было гвоздя


В свои bash-скрипты я вставляю
#!/usr/bin/env bash
set -euo pipefail



Опция -e останавливает скрипт если процесс вернул не 0 (и пишет в stderr на какой строке ошибка).

Это предотвращает беду, если в списке команд одна из фейлится:
svn up
build
copy some files
delete secret files
deploy build to external server

Опция -u останавливает скрипт, если используется неопределённая переменная. Это предотвращает беду например в таких случаях:

tar -czf download.tarball.tar.gz "$PROJECT_DIR/bin"

Если почему-то PROJECT_DIR не определена, то пакуется и отправляется пользователям системная /bin, вместо скомпилированых файлов проекта. И есть менеее забавные фейлы, превращение rm -rf "$1/$2" в rm -rf "/" со стиранием всего.

В комбинации с предыдущей опцией - опечатки в переменных окружения перестают быть непредсказуемым каскадно-гвоздевым фейерверком.
опция -o pipefail фейлит выполнение пайпа, если один из подкомпонентов выполняется с ошибкой. Например,
cat файл_который_не_существует | iconv -f cp1251 -t UTF-8 > результирующий файл.


Ожидаемые ошибки я игнорирую явно.
Если мне похрен на результат команды, вставляю || true после неё
cmd || true #'||' запускает вторую команду, если первая вернула не ноль. '||' можно читать "а иначе".

Если я удаляю папку, которая может не существовать, я явно проверяю что она есть перед удалением:
test -d dir_to_delete && rm -r dir_to_delete.

grep с пустым выводом возвращает код 1, и код ошибки 2 если есть реальная ошибка. Игнорирую коды меньше 2 явно:
cmd1 | (grep c || test $? -lt 2) | cmd2. # $? - код возврата,  test A -lt B - сравнение


Я не знаю, как удобным образом проверить ошибки в cmd2 в таком коде:
cmd1 $(cmd2)
. Подскажите?

Я не эксперт по "портабельному sh", поэтому если используете #!/bin/sh который ссылка на ksh/dash/bash/некий лже-POSIX, то надо смотреть в манах/гуглах какие есть опции.

В bat-файлах программировать надёжно сложно, и я не хочу внимательно вникать в cmd.exe, боюсь за свою психику.
Тем не менее, если я загоняю в bat-файл простой список команд, я в конце каждой команды ставлю || goto error или || exit /b 1 (или || pause если скрипт интерактивный, запускается всегда мышкой).

build || pause
copy some files || pause
delete secret files || pause
deploy build to external server || pause


Данная техника позволила в скрипте апдейта арта для дизайнеров найти тупые и хитрые ошибки в первые два месяца проекта (иначе бы мы с ними жили два года).

Ничего сложного на bat-файлах я стараюсь не писать, они в пять коварней чем C++, bash, assembler и perl вместе взятые.

Если не убеждаться в правильности работы каждой команды из цепочки, картинкиCollapse )

проверка пересечения: сведение к меньшим размерностям
nyaload
_winnie
Для объектов A и B со связной границей утверждение "А пересекается с B" эквивалентно "границы А и B пересекаются || A вложен в B || B вложен в А"

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

А и B должны быть со связной границей ( это ограничение самое важное при прикладном применении ). А так же замкнутыми, непустыми, и должны существовать точки вне A и B ( A|B не должно покрывать целиком всё пространство ).

Для полосок на торе, шайб-колец в 2d, отрезков на одномерной прямой, утверждение не сработает, так как их граница не связна.
Условие что есть точки вне A и B тоже необходимо, иначе можно привести антипример A={(x,y)|x2+y2 <= 2}, B={(x,y)|x2+y2 >= 1} или арбуз упакованный в два презерватива.

Кстати, теорему придумал сам, но наверное тоже баян, так как учебников по топологии не читал.

exceptions
nyaload
_winnie
1. Относительно checked exceptions в Java (список разрешённых исключений в декларации метода):
у меня нет проблем с мего-списком исключений, такой список от непонимания кода и непонимания как транслировать исключения. И от того, что Read more...Collapse )

2. Моя точка зрения на жизнь с исключениями:
Read more...Collapse )

3. Геймдевелоперы живут без исключений, они им не нужны, Read more...Collapse )

bithacks
nyaload
_winnie
Выяснилось, что битовые операции для быстрого нахождения логарифмов и тп часто считаются мистикой, люди их боятся, старшие программисты заменяют на "простые понятные циклы, вдруг рванёт из потустороннего мира".
Ничего мистического тут нет, надо просто думать о числе как о контейнере битов, и помнить школьные правила сложения/вычитания в столбик. Битовые &|~ >> << дают очевидные операции над контейнером. Сложение и вычитание – дают предсказуемые операции, когда нет переноса в старший разряд. Или когда из круглого числа с хвостом нулей вычитают 1, то получаем такой же хвост из 12 (в десятичной системе – из девяток). Например, xyz5000 - 1 == xyz4999.

Вкратце (и нестрого) про представление отрицательных чисел. В байте могут храниться значения от -128 до 127. Read more...Collapse )(Без)знаковость в арифметических операциях на биты не влияет, если нам удобно думать что числа от -1 до 254 или от -100 до 155, то пожалуйста, только сравнение будет своё, а +-* можно оставить.

Неочевидных арифметических трюков мало, самые часто использующиеся - это равенство (~x + 1) == (0 - x) и определение знака числа через x >> 31 (>>63 для 64-битных, >>7 для signed byte и тп).
  1. Первое равенство (~x + 1) == (0 - x) получается вычитанием в столбик. Вычтем из байта 11111111 число xxxxxxxx, 1-x даёт инверсию бита x. Вычитание из 11111111 это вычитание из представления -1. Таким образом -1-x == ~x.

  2. Второе равенство следует из определения побитового сдвига для знаковых чисел. Когда биты сдвигаются вправо, надо чем-то заполнять место слева. Для безнаковых чисел туда кладуться просто нули, а для знаковых – старший бит, что бы сохранился знак числа. Таким образом, число (Yxxxxxxx >> 7) превратится в YYYYYYYY, то есть в 0 или в -1. Также, если у нас есть выражение mask, которое равно -1 или 0, то mask xor x равно либо x, либо ~x.

  3. Так же постоянно используется прием (трюком это сложно назвать, слишком просто) замены (a ? x : y) на (a_mask & x) | (~a_mask & y), где a_mask это 00000000 или 11111111.

Давайте разберём несколько примеров.
1) Абсолютное значение числа.Read more...Collapse )
2) является ли число степенью двойки. Очень красивое решение: Read more...Collapse )
3) округление до следующей степени двойки. Read more...Collapse )
4) Подсчёт числа битов. Read more...Collapse )
5) логарифм числа (т.е. позиция старшего бита, номер мип-мапа, глубина двоичного дерева, количество шагов в делении пополам и тд).Read more...Collapse )
Уф, я устал, больше хаков смотрите здесь:
http://graphics.stanford.edu/~seander/bithacks.html
Если будете копировать код, подумайте, считать ли 0 степенью двойки или есть ли у 0 осмысленный логарифм.

Интересы друзей, из командной строки
nyaload
_winnie
Список интересов друзей в ЖЖ, однострочником на bash.
Как обычно для bash, без обработки исключительных ситуаций, без дополнительных плюшек нормирования по популярности интересов, зато в одну строку :)

wget http://www.livejournal.com/misc/fdata.bml?user=_winnie -q -O - | grep '^> ' | cut -c 3- | while read friend ; do wget http://www.livejournal.com/misc/interestdata.bml?user=$friend -q -O - ; done | sed -n 's#[0-9]\+ [0-9]\+ \(.*\)#\1#p' | sort | uniq -c | sort -k 1 -n

Названия переменных в динамических ЯП
nyaload
_winnie
1. Квадрат длины вместо длины 3d-вектора.
Известная многим фишка оптимизации при сравнении длин векторов, вкратце расскажу про неё.
Пусть у нас есть 3d-вектора. Многие помнят как вычислять его длину - sqrt(x2+y2+z2). Часто в коде надо сравнивать длины векторов (найти самого близкого противника и тп).

Код вида Point3d direction1, direction2; direction1.length() < direction2.legnth()) вычисляет два квадратных корня, можно смело заменять его на direction1.lengthSquared () < direction2.lengthSquared ()), где lengthSquared не извлекает корень из x2+y2+z2. Что может быть раз в 10 быстрей.

2. Сюрприз при скриптинге. 100 тактов FPU против хеш-таблиц. .
В нашем движке, экспортированные из C++ для python 3d-вектора имеют методы length и lengthSquared. И в документации постулируется, что лучше вызывать lengthSquared когда надо сравнить длины векторов, типа это быстрей и корень не извлекается. Проверил это, и получил сюрприз - lengthSquared оказался на 5% медленней чем length. Объяснение простое - все поля/методы объекта в python это строки в хеш-таблице. Строка "lengthSquared" длинней чем "length". И суета с длиной идентификатора в хеш-таблице оказалась важней чем наличие квадратного корня. Вывод - в динамическом ЯП неважно что звать, вычисление "сложного" синуса или тупое сложение. Если хотим выжать сколько-то (десятков) процентов скорости не переписывая на C - стоит класть методы объектов в локальные переменные, ls = Point3d.lengthSquared; ls(dir1) < ls(dir2);

3. Сюрприз при скриптинге - 2. Глобальные переменные против локальных. .
Доступ к глобальной переменной в питоне - достаточно долгая операция. Питону нужно проверить пачку вложеных неймспейсов, что бы найти глобальную переменную, причем по строковому имени.
Доступ к локальным переменным - гораздо быстрей, без поисков по хеш-таблицам ( строка превращается в индекс при генерации байт-кода ).
У нас много всяких Enum, часто код насыщен использованием enum-типа вроде
Moving.Direction.NORTH, Moving.Direction.SOUTH, Moving.Direction.EAST, Moving.Direction.WEST.
После присваивания Moving.Direction в локальную переменную
Dir = Moving.Direction; Dir.NORTH, Dir.SOUTH, Dir.EAST, Dir.WEST
опять же выигрывал десятки процентов по производительности.
Разрушением картины миры для моего коллеги так же стало, что код при переписывании со строк на enum ( напр. MoveObject("EAST") на MoveObject(Moving.Direction.EAST)) замедлился. У него после C++ в голове не укладывалось, что использование строк может быть быстрее, чем целочисленного enum. А причина была именно в том, что Moving.Direction.EAST - это аж три поиска строк по хеш-таблицам, причем первый - в глобальном namespace с сотнями глобальных имен.
По той же причине for i in range(1000*1000): j = i*i перенесённый из глобальной области в функцию тоже может сильно ускориться (переменные i,j из глобальных станут локальными).