Mikle
Ну как в фотошопе хотел. Или не так должно быть?
Я может не ту логику применяю.
Я ожидал, что если есть спрайт, который полностью прозрачный, если на него рисовать частично не прозрачный спрайт, то те пиксели (пиксели спрайта который рисуешь) у которых альфа больше 0 наложатся поверх
вот я сделал пример
вот код
Sprite sp_back1 = new Sprite(320, 320);
sp_back1.ClearBuffer(0);
Sprite sp_back2 = new Sprite(320, 320);
sp_back2.ClearBuffer(0);
Sprite sp_checker = new Sprite(@"r:\sprite_checker.png");
sp_back1.Draw(sp_checker, 20, 20, SR2D.Op.AlphaBlend);
sp_back2.Draw(sp_checker, 20, 20, SR2D.Op.AlphaTest);
sp_back1.SaveToFile("_sprite_alpha_blend.png", System.Drawing.Imaging.ImageFormat.Png, true);
sp_back2.SaveToFile("_sprite_alpha_test.png", System.Drawing.Imaging.ImageFormat.Png, true);может я логику не правильную применяю, но альфа тест же работате как я ожидаю, почему альфа бленд, там где 255, просто всё 0 остается.
SilentPrayerCG
> почему альфа бленд, там где 255, просто всё 0 остается.
Потому, что альфабленд не трогает альфаканал. Если сохранять в файл с выключенной альфой - будет вполне нормальная картинка.
А вот правильное это поведение, или нет - вопрос открытый, и фотошоп тут, боюсь, не ориентир. Он, например, в тех местах, где альфа равна нулю, уничтожает информацию о цвете, в результате, если такой спрайт отображать с масштабированием, то на краях изображения получаются артефакты.
Ну а с альфатестом всё просто - это вообще не блендинг, а трафарет, либо старое изображение, либо новое.
Напиши, какое практическое применение ты планируешь, тогда станет понятнее, как правильно.
Например - нужно скомбинировать несколько спрайтов в один, условно, из деревьев сделать лес, чтобы накладывать его одним действием. Для этой задачи никакой стандартный вариант работы с альфаканалом не подходит, я когда-то занимался этим вопросом, и в самом первом SR2D был оператор AlphaCombine с довольно сложной формулой.
Mikle
Ну вот допустим, у меня есть спрайт с полупрозрачностью и я хочу его нарисовать на пустом спрайте, сохранив при этом полупрозрачность, сейчас то это не получится же.
SilentPrayerCG
> у меня есть спрайт с полупрозрачностью и я хочу его нарисовать на пустом спрайте, сохранив при этом полупрозрачность
Можно нарисовать с помощью OpPaint - перенесёт всё, включая альфаканал.
Mikle
OnPaint это оператор?
я сейчас просто не пойму что вообще происходит если на прозрачном спрайте рисовать...
типа альфа не смешивается вообще..., в моем понимании если в спрайте куда рисуешь альфа 0, а ты рисуешь спрайтом у которого альфа 128, то в этой точке будет 128 а не 0
а если спрайт на котором рисуешь 128 альфа, а ты рисуешь альфой 30, то видимо должна быть альфа больше 128, я так понимаю по формуле альфабленда.. где-то у меня была она... не могу найти
в общем я сделал еще тест с bitmap и graphics
и вот там оно по умолчанию ведет себя так как я ожидал
я еще сделал шашечки в центре полупрозрачными
Bitmap bmp0 = new Bitmap(320, 320);
Bitmap bmp1 = new Bitmap(@"r:\sprite_checker.png");
bmp0.SetResolution(72, 72);
bmp1.SetResolution(72, 72);
Graphics gra = Graphics.FromImage(bmp0);
gra.Clear(Color.FromArgb(0));
gra.DrawImage(bmp1, 20, 20);
bmp0.Save(@"r:\___BMP_ALPHA_TEST.png", System.Drawing.Imaging.ImageFormat.Png);и теперь странность... если стоит альфа ТЕСТ, то почему-то на выходе ПОЛУпрозрачность сохраняется, т.е поведение которое я ожидал от альфаБЛЕНДа в данном случае 🤔
SilentPrayerCG
> если стоит альфа ТЕСТ, то почему-то на выходе ПОЛУпрозрачность сохраняется, т.е поведение которое я ожидал от альфаБЛЕНДа в данном случае
Ты путаешь полупрозрачность, как свойство картинки, с полупрозрачностью в операторе наложения.
Первое - это просто наличие альфаканала, а второе - это блендинг по альфе источника при наложении. Формула такая:
cD=cS*aS+cD*(1-aS)
cD - Color Dest, aS - Alpha Src и т. д. Числа из диапазона 0..255 приведены к 0..1 float.
То есть:
R=RS*aS+RD*(1-aS) G=GS*aS+GD*(1-aS) B=BS*aS+BD*(1-aS)
Это три цветовые компоненты. Если так же наложить и альфу:
a=aS*aS+aD*(1-aS)
То мы на месте альфы получим её квадрат (если aD=0, как в твоём первом примере), в любом случае - на то значение, которое тебе требуется.
SilentPrayerCG
> если спрайт на котором рисуешь 128 альфа, а ты рисуешь альфой 30, то видимо должна быть альфа больше 128
a=(30/255*30/255+128/255*(1-30/255))*255=116,470588235294
Как видишь, выходит меньше 128.
Ладно, пускай так будет. Я уже запутался.
SR2D
Public Sub SetLockRect(Optional ByVal LRLeft As Integer = -1, Optional ByVal LRRight As Integer = -1, Optional ByVal LRTop As Integer = -1, Optional ByVal LRBottom As Integer = -1)
If LRLeft >= 0 And LRLeft < meWidth Then meLeft = LRLeft Else meLeft = 0
If LRRight > LRLeft And LRRight <= meWidth Then meRight = LRRight Else meRight = meWidth
If LRTop >= 0 And LRTop < meHeight Then meTop = LRTop Else meTop = 0
If LRBottom > LRTop And LRBottom <= meHeight Then meBottom = LRBottom Else meBottom = meHeight
End Sub
тут есть довольно грубая ошибка (извиняюсь за резкость устал искать) которая позволяет задать отрицательную границу которая например при рисовании линии с отриц значением позволет послать в DLL задачу в которой правая граница может быть левее и низ выше верха из за чего жёсткий ступор вплоть до синего экрана иногда получается.
Сегодня случайно словил когда скроллинг колёсика мыши наконец сделал и стал проекции гонять в хвост и гриву в результате чего словил копытом по системному блоку от этой ошибки
И теперь из принципа не скажу в чём ошибка в ближайшее время - маленькая мстя после целого дня отслеживания этой ошибки!!!!!!!!!
для справки в SR2D версии 3.2 то же самое:
Public Sub SetLockRect(Optional ByVal Left As Long = -1, Optional ByVal Right As Long = -1, Optional ByVal Top As Long = -1, Optional ByVal Bottom As Long = -1)
If Left >= 0 And Left < meWidth Then meLeft = Left Else meLeft = 0
If Right > Left And Right <= meWidth Then meRight = Right Else meRight = meWidth
If Top >= 0 And Top < meHeight Then meTop = Top Else meTop = 0
If Bottom > Top And Bottom <= meHeight Then meBottom = Bottom Else meBottom = meHeight
End Sub
лишний текст пока не убрал - устал после мозгового штурма и множестВА вылетов системы
и да кстати нашёл способ отслеживать скроллинг колеса мыши в VB6 и этот способ в других языках работает тоже. Способ защищён от зависания очереди сообщений системы и работает в разных окнах. В общем балуясь этим скролингом и смог задать условия для срабатывания ошибки случайно гоняя проекции разных объектов в визуальном пространстве
Neirapik
> нашёл способ отслеживать скроллинг колеса мыши в VB6 и этот способ в других языках работает тоже
Да я уже давно пользуюсь таким, код формы:
Option Explicit
Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" (ByRef lpMsg As WinMSG, ByVal hWnd As Long, ByVal uMsgFilterMin As Long, ByVal uMsgFilterMax As Long, ByVal uRemoveMsg As Long) As Long
Private Declare Function WaitMessage Lib "user32" () As Long
Private Type WinMSG
hWnd As Long
uMessage As Long
wParam As Long
lParam As Long
dwTime As Long
mX As Long
mY As Long
End Type
Const PM_NOREMOVE As Long = 0
Const WM_MOUSEWHEEL As Long = &H20A
Const PM_REMOVE As Long = 1
Dim MSG As WinMSG
Dim Wheel As Long
Private Sub Form_Load()
Me.Show
While DoEvents
WaitMessage
If PeekMessage(MSG, hWnd, WM_MOUSEWHEEL, WM_MOUSEWHEEL, PM_REMOVE) Then
If MSG.wParam < 0 Then
Form_MouseWheel -1
Else
Form_MouseWheel 1
End If
End If
Wend
End Sub
Sub Form_MouseWheel(ByVal nScroll As Long)
Wheel = Wheel + nScroll
Me.Caption = Wheel
End SubNeirapik
> есть довольно грубая ошибка (извиняюсь за резкость устал искать) которая позволяет задать отрицательную границу
Что-то не могу подобрать параметры. Дай пример входных данных для ошибки.
И, даже если так, это не столько ошибка, сколько уязвимость.
Sr2D 3.2 32бит
Private Sub Command1_Click()
Dim Spr2 As New SR2D_Sprite
Spr2.Init 500, 500
Spr2.ClearBuffer 0
Spr2.SetLockRect 300, 379, -9, -7
Spr2.DrawLine 310, -9, 370, 6, 255
End Sub
запускал из VB6. редактор виснет и закрыть получается только через аварийное окошко
компилированный exe не пробывал запускать
у примера с мышкой интересный спецэффект - форма открывается снова если закрыть
надо будет это завернуть в UserControl с внешним видом как у таймера только вместо секундомера мышку нарисовать
завернул и работает, но теперь другой фокус покус - работает только один экземпляр тот который последний запущен, и в режиме редакции т.к. является контролом тоже запускается но не отлавливает событие
и при потере фокуса у окна на котором находится контрол событий колеса мыши - события перестают отлавливаться. При возврате фокуса на форму счётчик поворотов колеса снова начинает работать.
Вывод: способ работает только для одной формы
Neirapik
> у примера с мышкой интересный спецэффект - форма открывается снова если закрыть
Странно. Почему у меня не открывается?
SetLockRect, навскидку, правильнее так:
Public Sub SetLockRect(Optional ByVal Left As Long = -1, Optional ByVal Right As Long = -1, Optional ByVal Top As Long = -1, Optional ByVal Bottom As Long = -1) If Left >= 0 And Left < meWidth Then meLeft = Left Else meLeft = 0 If Right > meLeft And Right <= meWidth Then meRight = Right Else meRight = meWidth If Top >= 0 And Top < meHeight Then meTop = Top Else meTop = 0 If Bottom > meTop And Bottom <= meHeight Then meBottom = Bottom Else meBottom = meHeight End Sub