Seryoga 184 Опубликовано: 13 февраля, 2016 (изменено) Последнее время пишется очень много GUI библиотек для open computers. Я решил не отставать от моды и начал разрабатывать свою библиотеку. Так как все гонятся за красивостью и универсальностью, я решил сделать упор на скорость рисования 2D объектов и их математических представлениях. В этой библиотеке содержится описание примитивных математических объектов: https://gist.github.com/DeveloperHacker/18e08fdfc2269f1ad5c8 Вектор Важно!! не изменяйте вручную поля классов. Это может привести к неопределённым ошибкамVector:new(x, y): Vector -- создаёт вектор с координатами x, yVector:clone(): Vector -- создаёт копию текущего вектораVector:sabs(): Double -- возвращает квадрат модуля вектораVector:abs(): Double -- возвращает модуль вектораVector:__add(v): Vector -- возвращает результат сложения двух векторовVector:__sub(v): Vector -- возвращает результат вычитания двух векторовVector:__mul(v): Double -- возвращает число, где знак это направление вектора результата, а модуль -- модуль этого вектораVector:__unm(v): Vector -- возвращает противоположный векторVector:dot(v): Double -- возвращает скалярное произведение двух векторовVector:cos(v): Double -- возвращает косинус угла между векторамиVector:scale(a): Vector -- возвращает вектор в а раз больший текущегоVector:rotate(theta): Vector -- возвращает вектор повёрнутый на theta радиан относительно данного вектораVector.ceil(v): Vector -- возвращает вектор у которого координаты округлены до целогоVector:equals(v): Boolean -- возвращает результат сравнения двух векторовVector:toString(): String -- приводит вектор к строкеVector:print(): void -- выводит координаты вектора Отрезок Важно!! не изменяйте вручную поля классов. Это может привести к неопределённым ошибкамSection:new(p1, p2): Section -- создаёт новый отрезок с концами в точках p1, p2Section:clone(): Section -- создаёт копию текущего отрезкаSection:IsInside(p): Boolean -- возвращает результат проверки включения точки p отрезкуSection.intersection(s1, s2): Boolean -- возвращает результат проверки пересечения двух отрезковSection:equals(v): Boolean -- возвращает результат сравнения двух отрезковSection:toString(): String -- приводит отрезок к строкеSection:print(): void -- выводит координаты отрезка Линия Важно!! не изменяйте вручную поля классов. Это может привести к неопределённым ошибкамLine:new(s): Line -- создаёт линию проходящую через отрезок sLine:solve(p): Double -- ... Line:y(x): Double -- ...Line:x(y): Double -- ...Line:equals(l): Boolean -- возвращает результат сравнения двух прямыхLine:toString(): String -- приводит линию к строкеLine:print(): void -- выводит уравнение прямой Ломаная Важно!! не изменяйте вручную поля классов. Это может привести к неопределённым ошибкамPolyline:new(pos, outline): Polyline -- создаёт новую ломаную в точке pos где координаты остальных вершин находятся по координатам относительно точки pos, которые содержатся в массиве outline Polyline:add(v): void -- добавляет координаты новой вершины Polyline:equals(poly): Boolean -- возвращает результат сравнения двух ломаных Многоугольник Важно!! не изменяйте вручную поля классов. Это может привести к неопределённым ошибкамPolygon:new(polyline): Polygon -- создаёт новый полигон на основе ломануюPolygon:rectangle(pos, width, height): Polygon -- создаёт прямоугольникPolygon:rightFigure(pos, qVertexes, radius, theta): Polygon -- создаёт правильную фигуру, где theta -- это угол отклонения первого угла от нормали Polygon:convex(): Boolean -- возвращает результат проверки, того что полигон является выпуклымPolygon:height(): Double -- рассчитывает высоту полигона, лучше использовать поле с таким же названием Polygon:width(): Double -- рассчитывает ширину полигона, лучше использовать поле с таким же названиемPolygon:isInside(v): Boolean -- проверяет принадлежит ли точка полигонуPolygon:center(): Vector -- рассчитывает координаты центра полигона, лучше использовать поле с таким же названием Polygon:rotate(origin, theta): Polygon -- возвращает результат поворота полигона на theta радиан относительно точки origin А также есть классы, которые участвуют в рисовании: https://gist.github.com/DeveloperHacker/c54e3442202274b0ca9a Цвет RGBA Color.decode©: int, int, int, int -- раскодирует укороченную запись цвета rgbaColor.code(r, g, b, a): hex -- создаёт укороченную запись цвета rgba Color.decodeRGB©: int, int, int -- раскодирует укороченную запись цвета rgbColor.codeRGB(r, g, b): hex -- создаёт укороченную запись цвета rgbColor.toRGBA(rgb, a): hex -- создаёт укороченную запись цвета rgba на основе rgb и его alpha-канале 0 <= a <= 255 Color.toRGB(rgba): hex -- создаёт укороченную запись цвета rgb на основе rgbaColor.mix(c1, c2): hex -- возвращает значение выражения (c1.alpha) * c1.rgb + c2.rgb, реализует полупрозрачное наслоение цвета c1 на цвет c2 Matrix для рисования низкоуровневых объектов Важно!! не изменяйте вручную поля классов. Это может привести к неопределённым ошибкамMatrix:new(x, y, w, h, gpu): Matrix -- создаёт новую матрицу, x, y координаты (в пикселях) позиции матрицы на экране Matrix:paint(): void -- рисует новые объекты на экранMatrix:repaint(): void -- полностью перерисовывает матрицу Matrix:setBackground(rgba): void -- изменяет цвет фонаMatrix:setBrush(rgba): void -- изменяет цвет кисти Matrix:drawPixel(x, y): void -- рисует пиксель на матрицуMatrix:drawLine(x1, y1, x2, y2, drawEndPixel): void -- рисует линию на матрицу, если drawEndPixel = false, то не отображается последний пиксель. Matrix:drawPolyline(vectors): void -- рисует ломаную на матрицу, где в массиве vectors расположены вершины ломаной Matrix:drawPolygon(vectors): void -- рисует полигон на матрицу, где в массиве vectors расположены вершины полигонаMatrix:clear(): void -- очищает матрицуMatrix:clone(): Matrix -- копирует матрицуMatrix:revert(prev): void -- откатывает матрицу self до матрицы prev Painter для рисования высокоуровневых объектов Важно!! не изменяйте вручную поля классов. Это может привести к неопределённым ошибкамPainter:new(matrix, pos): Painter -- создаёт нового художника, где pos -- позиция матрицы в пространстве, где заданы фигуры Painter:drawPoint(vector): void -- рисует точку на матрице Painter:drawLine(section): void -- рисует линию на матрицеPainter:drawPolyline(polyline): void -- рисует ломаную на матрицеPainter:drawPolygon(polygon): void -- рисует полигон на матрице Вспомогательные программки без которых сложно, что либо проектировать: https://gist.github.com/DeveloperHacker/5f4925b04a9524790036 Расширение gpu Future description Программа для быстрой смены цвета текста и фона консоли, можно добавить изменение разрешения Future description Программы для запуска файлов с расширением Future description Пример работы с моей библиотекой: https://gist.github.com/DeveloperHacker/cc84c09a0980fcd21472 Рисование при помощи матрицы Future description Рисование при помощи painter'а Future description В планах: Написать документацию Добавить проверку соседних пикселей Добавить закрашивание фигур Добавить рисование растровых изображений Добавить класс Intersector, он будет специализироваться на обнаружении наложений объектов и их пересечении Добавить сохранение матрицы в растровом и векторном виде Добавить закрашивание фона фигур и матрицы растровым изображением Попробовать уменьшить пиксели до половины, как это сделал Zer0Gelaxy http://computercraft.ru/topic/1451-graficheskaia-biblioteka-graffiti/?do=findComment&comment=20699 Добиться максимальной производительности Написать небольшой проект использующий эту библиотеку Реализовать 3D Писал это библиотеку максимально гибко, поэтому возможна интеграция с другими Gui lib'ами. Если вам она понравиться, то я продолжу разработку в ускоренном темпе. Не откажусь от чьей либо помощи. Надеюсь вам понравится. P.s моя реализация похожей библиотеки на языке java https://github.com/DeveloperHacker/2DEngine Изменено 15 февраля, 2016 пользователем Seryoga 5 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Krutoy 1 169 Опубликовано: 14 февраля, 2016 Векторная отрисовка - отличная идея. Но пока ничего не ясно. Не видно примеров, ни скриншотов, ни сравнения производительности с готовыми решениями. Пожалуйста, добавь эти три пункта в первый пост. И не ссылками, а прямо на форуме. 2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fingercomp 4 409 Опубликовано: 14 февраля, 2016 Используйте Gist, который в одном гисте может хранить тучу файлов, для скачивания же вот прога. А то мало того, что пост не до конца оформлен, так ещё и хост, с которого выгружал, заблочил. Ну и скриншоты, доки, сравнения и человекочитаемый текст обязательно. Набор ссылок — meh. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
LeshaInc 625 Опубликовано: 14 февраля, 2016 Либа прикольная, только какой в ней смысл не понятно. Очень хочется вставить эту картинку: А так норм, сменя лайк и плюсик в репку. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Seryoga Автор темы 184 Опубликовано: 14 февраля, 2016 (изменено) Либа прикольная, только какой в ней смысл не понятно. Попробуй запустить файл painter.test. Там ты увидишь два двигающихся объекта и много статических. + один из этих объектов полупрозрачный. Когда перемещаются эти объекты экран не мигает. Простота анализа пересечений объектов. Например чтобы проверить пересекаются ли два прямоугольника, нужно написать кучу проверок. Здесь тебе нужно задать два прямоугольника и в цикле проверить входят ли углы одного прямоугольника в другой. При помощи метода isInside(Vector): Boolean. В будущем я добавлю функции по типу intersectionFF(Polygon2d, Polygon2d): Boolean и intersectFF(Polygon2d, Polygon2d): Polygon2d Объекты заданные векторно легко масштабируются, перемещаются, искривляются, поворачиваются и мн. др. Это всё упростит разработку редакторов и игр на луа и др... Все тесты с циферками приведу позже, пока что все оценки скорости на глазок. Очевидно, что полное перерисовывание экрана каждый такт менее производительно, чем частичное перерисовывание. Изменено 14 февраля, 2016 пользователем Seryoga 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Seryoga Автор темы 184 Опубликовано: 14 февраля, 2016 (изменено) Added an description of vector2dAdded an description of section2dAdded an description of line2dAdded an description of polyline2dAdded an description of polygon2d Изменено 14 февраля, 2016 пользователем Seryoga Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
LeshaInc 625 Опубликовано: 14 февраля, 2016 ........................ы.ыыыыыыыы...................... Я понимаю что оно делает, я не понимаю зачем оно это делает. Кому нужны квадратики и кружочки? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Zer0Galaxy 2 187 Опубликовано: 14 февраля, 2016 Серега, не слушай Лёшу, пиши документацию. Мне, к примеру, пока не понятно, как векторная графика связана с GUI? 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Seryoga Автор темы 184 Опубликовано: 14 февраля, 2016 Added an description of colorAdded an description of pixelAdded an description of matrixAdded an description of painter Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
ECS 1 903 Опубликовано: 14 февраля, 2016 (изменено) Начнем с того, что тут мы имеем крайне медленную и неоптимизированную отрисовку: цвет фона меняется каждую итерацию в цикле. Например, если мы имеем в памяти линию красного цвета длиной в 150 пикселей, то куда грамотнее будет разово изменить цвет фона на красный, а затем выполнить gpu.fill(), нежели выполнять 150 итераций со сменой цвета и установкой пикселя (скриншот кода с гиста автора ниже). Это нехитрое действо сократит количество GPU-операций в десятки и сотни раз, учитывая размеры мониторов. Далее рассмотрим таблицу matrix: во-первых, это трехмерный массив, что уже сильно повышает расход оперативной памяти: куда выгоднее сделать одномерную таблицу с последующим получением из нее нужных индексов. Во-вторых, в каждой подтаблице имеется отдельная boolean-переменная, отвечающей за смену пикселя. Это шутка такая? Боюсь себе представить, сколько памяти сжирают эти махинации. Сильно не люблю критиковать других людей, но заявленным "упором на скорость рисования 2D-объектов" тут даже близко не пахнет. Плюс, реализация библиотеки с пародией на ООП лично у меня вызывают лютое отвращение: неудобно, некрасиво, куча лишнего кода при создании программ, бр-р-р. Кроме того, на форуме уже есть прекрасная графическая GML-либа: названия ее методов просты как божий день, да и графика рисуется в разы быстрее. Также рекомендую либу двойного буфера для максимальной скорости рисования. В общем, шли бы лучше игрушки кодить для опенкомпов - и детишкам понравилось бы, и критики никакой не услышали бы, игры любят все, в любом виде! Изменено 14 февраля, 2016 пользователем ECS 2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Seryoga Автор темы 184 Опубликовано: 14 февраля, 2016 (изменено) Крайне медленная и неоптимизированная отрисовка, цвет фона меняется каждый раз без проверки на соседние пиксели. Например, если мы имеем в памяти линию красного цвета длиной в 150 пикселей, то куда грамотнее будет разово изменить цвет фона на красный, а затем выполнить gpu.fill( ), нежели выполнять 150 итераций со сменой цвета (скриншот кода с гиста автора ниже). Это сократит количество GPU-операций в десятки и сотни раз, учитывая размеры мониторов. Так что "упором на скорость рисования 2D объектов" тут даже близко не пахнет, да и реализация библиотеки с упором на ООП у меня лично вызывают лютое отвращение: неудобно, некрасиво, бр-р-р. Кроме того, на форуме уже есть прекрасная графическая GML-либа: она написана куда приятнее, названия методов просты как божий день, да и прорисовка работает быстрее. Также рекомендую либу двойного буфера для максимальной скорости рисования. Шли бы лучше игрушки кодить для опенкомпов - и детишкам понравилось бы, и критики никакой не услышал бы, игры любят все! Если тебе захочется нарисовать огромный прямоугольник, то можно сделать это за 1 операцию XD Упор идёт на динамические структуры. Я не спорю можно сделать анализ соседних пикселей, это в среднем сократит количество операций вдвое, хотя не факт. Так для рисования больших прямоугольников лучше использовать скомпилированные функции. Над чем я и работаю, просто сюда не добавил. Так как очень сырые. Ты нарисуешь один раз кучу объектов, подождёшь 0.1 сек, а дальше будет изменение 1 - 10 пикселей. Преимущества векторизации: Возможность создания view-портов, что позволит только перемещать матрицу в мире, а не объекты. Сейчас работаю над созданием матрицы у которой контур не прямоугольник, а полигон, что позволит создавать необычные сцены. Код легко расширяем, например чтобы сделать анализ соседних пикселей, я могу сопенсорсить твою функцию draw. Изменено 14 февраля, 2016 пользователем Seryoga Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
ECS 1 903 Опубликовано: 14 февраля, 2016 (изменено) Ты нарисуешь один раз кучу объектов, подождёшь 0.1 сек, а дальше будет изменение 1 - 10 пикселей. А пиксели эти будут рисоваться с постоянной сменой цвета и фона, ага. Допустим, на экране изменился прямоугольник 5х2 синего цвета. Как будет работать твой код? Правильно, он выполнит 10 раз операцию gpu.setBackground() и 10 раз операцию gpu.set(), в то время как можно было бы всего лишь gpu.setBackground(); gpu.fill(). Напомню, каждая операция видеокарты - это реальные игровые тики, и при таком подходе к отрисовке любая более-менее сносная игра у тебя попросту будет фризится. Кроме того, как я и сказал выше, у тебя крайне неразумен расход памяти. Надо скачать ради интереса твою либу и проверить, сколько памяти она сжирает при полноэкранных 160х50 отрисовках. Интересно, вылетит out of memory или нет? Как знать, как знать! P.S. Боже упаси, 823 кбайта памяти сожрало! Изыди, изыди! Изменено 14 февраля, 2016 пользователем ECS 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Seryoga Автор темы 184 Опубликовано: 14 февраля, 2016 (изменено) А пиксели эти будут рисоваться с постоянной сменой цвета и фона, ага. Допустим, на экране изменился прямоугольник 5х2 синего цвета. Как будет работать твой код? Правильно, он выполнит 10 раз операцию gpu.setBackground() и 10 раз операцию gpu.set(), в то время как можно было бы всего лишь gpu.setBackground(); gpu.fill(). Напомню, каждая операция видеокарты - это реальные игровые тики, и при таком подходе к отрисовке любая более-менее сносная игра у тебя попросту будет фризится. Кроме того, как я и сказал выше, у тебя крайне неразумен расход памяти. Надо скачать ради интереса твою либу и проверить, сколько памяти она сжирает при полноэкранных 160х50 отрисовках. Интересно, вылетит out of memory или нет? Как знать, как знать! Хорошо, в ближайшие дни добавлю анализ соседних пикселей. Изменено 14 февраля, 2016 пользователем Seryoga Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Seryoga Автор темы 184 Опубликовано: 15 февраля, 2016 pixel.lua удалён.Изменена структура матрицы. Теперь она одномерная. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах