forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   FAQ и уроки (http://forum.boolean.name/forumdisplay.php?f=110)
-   -   Скруглённые уголки на BlitzMax (http://forum.boolean.name/showthread.php?t=15930)

Randomize 28.11.2011 09:25

Скруглённые уголки на BlitzMax
 
Вложений: 3
Здравствуйте, дорогие друзья. На днях (а именно сегодня) мне понадобилась функция, рисующая прямоугольник с закруглёнными углами, которые я так люблю использовать в веб проектах. В последнее время вообще скругление уголков это стильно и молодёжно.
Современные тенденции не приемлют прямых углов! "DrawRect уже не торт!" - плачут блицеры.
Я решил не делать как хрены профессионалы из Blitz Community и не стал наследовать класс от TMax2DGraphics ради единственной функции. Я просто написал свою глобальную функцию.

Фич лист:
Управление отображением через SetColor, SetAlpha

Минусы:
Игнорирует установленные ранее режимы отрисовки: SetOrigin, SetViewport, SetRotation*, SetScale*
Насчёт последних двух - спорный вопрос о необходимости.

И собственно код функции:
Код:

Function DrawRoundedRect(x:Float, y:Float, width:Float, height:Float, radius:Float = 10)
        Local diametr:Float = (radius + radius)
        Local oldScale:Float[2] ' 0..1 x,y
        Local oldAngle:Float
        Local oldViewport:Int[4] ' 0..3 x,y,width,height
       
        '--- Store old settings
        oldAngle:Float = GetRotation()
        GetScale(oldScale[0], oldScale[1])
        GetViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3])
       
        SetRotation(0) ' no rotation
        SetScale(1, 1) ' no scale
       
        '--- Draw corners:
        ' left top
        SetViewport(x, y, radius, radius)
        DrawOval(x, y, diametr, diametr)
        ' right top
        SetViewport(x + width - radius, y, radius, radius)
        DrawOval(x + width - diametr, y, diametr, diametr)
        ' right bottom
        SetViewport(x + width - radius, y + height - radius, radius, radius)
        DrawOval(x + width - diametr, y + height - diametr, diametr, diametr)
        ' left bottom
        SetViewport(x, y + height - radius, radius, radius)
        DrawOval(x, y + height - diametr, diametr, diametr)
       
        '--- Restore viewport
        SetViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3])
       
        '--- Draw rects       
        DrawRect(x + radius, y, width - diametr, radius)' top
        DrawRect(x + width - radius, y + radius, radius, height - diametr)' right
        DrawRect(x + radius, y + height - radius, width - diametr, radius)' bottom
        DrawRect(x, y + radius, radius, height - diametr)' left
        DrawRect(x + radius, y + radius, width - diametr, height - diametr)' middle
       
        '--- Restore Scale, Rotation
        SetScale(oldScale[0], oldScale[1])
        SetRotation(oldAngle)
EndFunction

Немного комментариев помогут разобраться.


Надеюсь кому-либо пригодится :)
Семпл и скрины:

Harter 28.11.2011 15:34

Ответ: Скруглённые уголки на BlitzMax
 
Молодец, булчую!

Greymem 28.11.2011 15:39

Ответ: Скруглённые уголки на BlitzMax
 
Вопрос как твоё детище проглотит SetAlpha

Скорее всего будут видны не очень приятные куски овалов и прямоугольников.
Я бы использовал, если бы не этот неприятный момент.


Пардон, не увидел SetViewPort

Я использую:
Код:

Function DrawRoundRect(x:Int, y:Int, width:Int, height:Int, radius:Int = 10)
        DrawOval(x, y, radius, radius)
        DrawOval(x + (width - (radius)), y, radius, radius)
        DrawOval(x, y + (height - (radius)), radius, radius)
        DrawOval(x + (width - (radius)), y + (height - (radius)), radius, radius)
        DrawRect(x + (radius / 2), y, width - radius, height)
        DrawRect(x, y + (radius / 2), width, height - radius)
End Function

Те-же самые куски при частичной прозрачности. Но мне пока что нра. =)

moka 28.11.2011 17:59

Ответ: Скруглённые уголки на BlitzMax
 
Обычно используют элементы с текстурами, по сути те же углы - это квады, с текстурой на них (с маской или альфой).
Лучше использовать как раз квады, объединённые в один (3*3 квада), где лишь центральные и боковые будут скейлиться, а угловые нет. И натянуть текстуры из атласса как полагается.
Так будет более производительно, и главное красивее. На основе этого можно уже дальше разрабатывать разные элементы и стили для них, меняя текстуру. Или хотя бы использовать текстуру в виде маски, а используя SetColor уже задавать сам цвет.

Randomize 28.11.2011 22:19

Ответ: Скруглённые уголки на BlitzMax
 
Цитата:

Сообщение от MoKa (Сообщение 211533)
...

Время обязывало сделать очень быстро и без какой либо графики

Dzirt 28.11.2011 23:08

Ответ: Скруглённые уголки на BlitzMax
 
Накатал ровно за 7 минут )

Много с чем еще не дружит,но с Cls уже подружил:

Код:

Strict
Graphics 800,600,0,60
SetBlend (alphablend)

SetClsColor 68,68,68       

While Not KeyHit(key_escape)
Cls
       
        DrawRoundedRect(100,100,300,200,50)


Flip
Wend
End



Function DrawRoundedRect(x,y,w,h,round)
        'get curent cls color for rounded corners
        Local GetClsR       
        Local GetClsG
        Local GetClsB
        GetClsColor (GetClsR,GetClsG,GetClsB)
       
        'get curent drawing color
        Local GetR       
        Local GetG
        Local GetB
        GetColor (GetR,GetG,GetB)
       
        'Draw main rect body
        DrawRect x,y,w,h
       
       
       
        SetColor GetClsR,GetClsG,GetClsB
        'draw  corners
        DrawOval x-round/2,y-round/2,round,round
        DrawOval x-round/2,y+h-round/2,round,round
       
        DrawOval x+w-round/2,y-round/2,round,round
        DrawOval x+w-round/2,y+h-round/2,round,round
       
        SetColor GetR,GetG,GetB
        DrawOval x,y,round,round
        DrawOval x,y+h-round,round,round
       
        DrawOval x+w-round,y,round,round
        DrawOval x+w-round,y+h-round,round,round
       
End Function


Черный крыс 04.12.2011 06:37

Ответ: Скруглённые уголки на BlitzMax
 
Нубско

Вот мое решение...

ЗЫ Насчет констант не парьтесь, они для другой функции, и последний аргумент функции ни к чему не обязывает )))

ЗЗЫ Float2 - это вектор

Код:

Const ROUND_LEFT_UP:Int = 1
Const ROUND_LEFT_DOWN:Int = 2
Const ROUND_RIGHT_UP:Int = 4
Const ROUND_RIGHT_DOWN:Int = 8
Const ROUND_LEFT:Int = ROUND_LEFT_UP | ROUND_LEFT_DOWN
Const ROUND_RIGHT:Int = ROUND_RIGHT_UP | ROUND_RIGHT_DOWN
Const ROUND_UP:Int = ROUND_LEFT_UP | ROUND_RIGHT_UP
Const ROUND_DOWN:Int = ROUND_LEFT_DOWN | ROUND_RIGHT_DOWN
Const ROUND_ALL:Int = ROUND_LEFT | ROUND_RIGHT
Function DrawRectRound(x:Float, y:Float, w:Float, h:Float, radius:Float = 40.0, corner:Int = -1, flags:Int = ROUND_ALL)
 radius = Abs(radius)
 
 Select Sgn(corner)
  Case - 1 corner = Int(radius / 10.0) + 1
  Case 1 corner = Abs(corner)
  Case 0
  DrawRect(x, y, w, h)
  Return
 End Select
 
 DrawRect(x + radius, y, w - (radius * 2.0), h)
 DrawRect(x, y + radius, radius, h - (radius * 2.0))
 DrawRect(x + w - radius, y + radius, radius, h - (radius * 2.0))
 
 Local v1:Float2 = Null
 Local v2:Float2 = Null
 Local i:Int
 
 For i = 0 To corner
  Local ang:Float = 0.0 + ((90.0 / corner) * i)
  v2 = New Float2.ForAngle(ang)
  v2 = v2.MulS(radius)
  If v1
  DrawPoly([x + w - radius, y + h - radius, v1.x + x + w - radius, v1.y + y + h - radius, v2.x + x + w - radius, v2.y + y + h - radius])
  End If
  v1 = v2
  v2 = Null
  'DrawLine(x + w - radius, y + h - radius, v2.x + x + w - radius, v2.y + y + h - radius)
 Next
 
 v1 = Null
 v2 = Null
 For i = 0 To corner
  Local ang2:Float = 90.0 + ((90.0 / corner) * i)
  v2 = New Float2.ForAngle(ang2)
  v2 = v2.MulS(radius)
  If v1
  'DrawLine(v1.x + x + radius, v1.y + y + h - radius, v2.x + x + radius, v2.y + y + h - radius)
  DrawPoly([x + radius, y + h - radius, v1.x + x + radius, v1.y + y + h - radius, v2.x + x + radius, v2.y + y + h - radius])
  End If
  v1 = v2
  v2 = Null
 Next
 
 v1 = Null
 v2 = Null
 For i = 0 To corner
  Local ang3:Float = 180.0 + ((90.0 / corner) * i)
  v2 = New Float2.ForAngle(ang3)
  v2 = v2.MulS(radius)
  If v1
  'DrawLine(v1.x + x + radius, v1.y + y + radius, v2.x + x + radius, v2.y + y + radius)
  DrawPoly([x + radius, y + radius, v1.x + x + radius, v1.y + y + radius, v2.x + x + radius, v2.y + y + radius])
  End If
  v1 = v2
  v2 = Null
 Next
 
 v1 = Null
 v2 = Null
 For i = 0 To corner
  Local ang4:Float = 270.0 + ((90.0 / corner) * i)
  v2 = New Float2.ForAngle(ang4)
  v2 = v2.MulS(radius)
  If v1
  'DrawLine(v1.x + x + w - radius, v1.y + y + radius, v2.x + x + w - radius, v2.y + y + radius)
  DrawPoly([x + w - radius, y + radius, v1.x + x + w - radius, v1.y + y + radius, v2.x + x + w - radius, v2.y + y + radius])
  End If
  v1 = v2
  v2 = Null
 Next
End Function


Randomize 04.12.2011 10:26

Ответ: Скруглённые уголки на BlitzMax
 
Отличный пример который не работает. Браво, Diablo1909!

Хотя без злорадства скажу, что через DrawPoly решение действительно интересное, только вот быстрее ли выходит чем примитивами?
И да: DrawRectRound - такое название ни куда не годится. "ОтрисоватьПрямогульникКруг" - не звучит и смыслом не блещет.

Черный крыс 04.12.2011 22:13

Ответ: Скруглённые уголки на BlitzMax
 
2Randomize

Прежде чем, делать свои заключения - ты сначала в код вникни, а потом только высказывай свое фи.

1) Он и не будет работать, я же по русски написал что нужен тип вектора Float2, который содержит x и y - компоненты. Нормальный кодер опишет этот вектор без особых затруднений.

2) Насчет быстродействия, если тебе интересно - то проверь. В твоей функции происходит 8 (восемь!) вызовов функции DrawOval(), а затем погляди на исходник этой функции... сразу скажу моя функция минимум раз в 4-6 будет работать быстрее.

3) Насчет названия - это уже дело вкуса. Но позволю защитить свое название...
название функции - полностью соответсвует мышлению программиста.

DrawRectRound()
[Draw] - отрисовать, [Rect] - Прямоугольник, [Round] - скругленный.

Другими словами я название функции делю на 3 части : [Операция][Основное название функции][Модификатор функции]

Кто со мной не согласен - те пусть пишут всякие басни в названиях функций.

Не могу отказаться от соблазна покритиковать вышеописанный код :

1) GetClsColor() - заЧем ?

2) Любые операции с вьюпортами нежелательны, ибо не на всех видяхах работает.

3) Золотое правило : в любых функциях отрисовки чего-либо никогда нельзя менять аттрибуты отрисовки. Вы поглядите на официальные функции - там из атрибутов ничего не трогается. А если уж нужда заставляет менять то при завершении работы функции их всегда надо возвращать в исходное состояние (тоесть на момент, когда функция была вызвана).

ЗЫ Для особо одаренных, ниже привожу полностью рабочий код :

Код:


SuperStrict
 
Function DrawRectRound(x:Float, y:Float, w:Float, h:Float, radius:Float = 40.0, corner:Int = -1)
 radius = Abs(radius)
 
 Select Sgn(corner)
  Case - 1 corner = Int(radius / 10.0) + 1
  Case 1 corner = Abs(corner)
  Case 0
  DrawRect(x, y, w, h)
  Return
 End Select
 
 DrawRect(x + radius, y, w - (radius * 2.0), h)
 DrawRect(x, y + radius, radius, h - (radius * 2.0))
 DrawRect(x + w - radius, y + radius, radius, h - (radius * 2.0))
 
 Local v1:Float2 = Null
 Local v2:Float2 = Null
 Local i:Int
 Local inc:Float = 90.0 / corner
 
 For i = 0 To corner
  Local ang:Float = 0.0 + (inc * i)
  v2 = New Float2.ForAngle(ang)
  v2 = v2.MulS(radius)
  If v1
  DrawPoly([x + w - radius, y + h - radius, v1.x + x + w - radius, v1.y + y + h - radius, v2.x + x + w - radius, v2.y + y + h - radius])
  End If
  v1 = v2
  v2 = Null
 Next
 
 v1 = Null
 v2 = Null
 For i = 0 To corner
  Local ang2:Float = 90.0 + (inc * i)
  v2 = New Float2.ForAngle(ang2)
  v2 = v2.MulS(radius)
  If v1
  DrawPoly([x + radius, y + h - radius, v1.x + x + radius, v1.y + y + h - radius, v2.x + x + radius, v2.y + y + h - radius])
  End If
  v1 = v2
  v2 = Null
 Next
 
 v1 = Null
 v2 = Null
 For i = 0 To corner
  Local ang3:Float = 180.0 + (inc * i)
  v2 = New Float2.ForAngle(ang3)
  v2 = v2.MulS(radius)
  If v1
  DrawPoly([x + radius, y + radius, v1.x + x + radius, v1.y + y + radius, v2.x + x + radius, v2.y + y + radius])
  End If
  v1 = v2
  v2 = Null
 Next
 
 v1 = Null
 v2 = Null
 For i = 0 To corner
  Local ang4:Float = 270.0 + (inc * i)
  v2 = New Float2.ForAngle(ang4)
  v2 = v2.MulS(radius)
  If v1
  DrawLine(v1.x + x + w - radius, v1.y + y + radius, v2.x + x + w - radius, v2.y + y + radius)
  DrawPoly([x + w - radius, y + radius, v1.x + x + w - radius, v1.y + y + radius, v2.x + x + w - radius, v2.y + y + radius])
  End If
  v1 = v2
  v2 = Null
 Next
 
 Type Float2
  Field x:Float
  Field y:Float
 
  Method Delete()
  x = Null
  y = Null
  End Method
 
  Method Create:Float2(x:Float = 0.0, y:Float = 0.0)
  MemCopy(Varptr Self.x, [x, y], 8)
  Return Self
  End Method
 
  Method ForAngle:Float2(ang:Float)
  MemCopy(Varptr x, [Float(Cos(ang)), Float(Sin(ang))], 8)
  Return Self
  End Method
 
  Method MulS:Float2(s:Float)
  Return Create(x * s, y * s)
  End Method
 End Type
End Function
 
SetGraphicsDriver(GLMax2DDriver())
Graphics(1024, 768)
 
SetTransform()
SetBlend(ALPHABLEND)
SetAlpha(1.0)
SetColor(255, 255, 255)
SetLineWidth(1.0)
 
Local r:Float = 40.0, k:Float = 0.3
 
While Not KeyHit(KEY_ESCAPE)
 Cls
 r:+k
 If r > 80.0 Then k = -0.3
 If r < 0 Then k = 0.3
 DrawRectRound(MouseX(), MouseY(), 300.0, 200.0, r, 5)
 Flip()
Wend
 
End


Randomize 04.12.2011 23:53

Ответ: Скруглённые уголки на BlitzMax
 
Diablo, стой, ты не верно истолковал.
Фи я высказал только по поводу названии функции и целостности твоего примера.

На счёт производительности мне интересно вот что:
Для DrawPoly же используется массив. Насколько быстро происходит его заполнение и создаётся геометрия по нему. Я вот тут подумал может можно куда-либо кешировать готовые собранные твоей функцией Poly или игра не стоит свеч, как считаешь?

Цитата:

[Операция][Основное название функции][Модификатор функции]
Считаю что последний пункт в данном случае излишен, хотя на вкус и цвет...

Цитата:

ЗЫ Для особо одаренных, ниже привожу полностью рабочий код :
Особо одаренных? Ты презентуешь свою ф-цию или нет? На мой взгляд она должна работать "из коробки", ты так не считаешь?

И да, я тебе очень признателен за проявленный интерес - твоя функция крута и это бесспорно. Возможно я возьму её на вооружение с некоторыми переделками ;)

Черный крыс 05.12.2011 02:27

Ответ: Скруглённые уголки на BlitzMax
 
Особого прироста не будет, так как массив аллокируется в 24 байт, а это происходит быстро.

Основной тормоз функции - это расчеты синуса и косинуса.

Как тебе известно, стандартная функция DrawOval() - прежде чем отрисовать круг 64 раза вызовет функцию Sin() и еще столько же вызовит функцию Cos().
А если рисовать 8 кружочков - то получается 64 * 8 = 512 вызовов на каждую функцию!

В моей функции есть параметр "corner" который определяет количество ребер.
Если ребер например 5 то получится 5 * 4 = 20 вызовов функций Sin() и Cos().

Можно это дело оптимизировать - занести в кэш результаты вычислений Sin и Cos а затем подставить их. Тоесть это дело можно довести до 5 вычислений Sin и Cos при 5 ребрах. А можно еще при этом использовать функцию SinCos() - тогда пролизводительность еще удвоится.

Вобсчем, оптимизировать еще можно... =)

Randomize 06.12.2011 00:58

Ответ: Скруглённые уголки на BlitzMax
 
Вложений: 1
Воть :3

DrawPoly вызывается 1 раз!
Единственное косинусов/синусов много :C
Код:

Function DrawRoundedRect(x:Float, y:Float, width:Float, height:Float, r:Float = 30, segs:Int = 4)
        segs = Max(segs, 1)
        r = Max(r, 1)
       
        Local xy:Float[] = New Float[((segs * 4) + 8) * 2]
       
        Local fstep:Float = 90 / segs ' one step for draw corners
       
        Local wpos:Int = 0 ' writing position in xy:Float[] array
       
        ' lt corner
        xy[wpos] = x
        xy[wpos + 1] = y + r
        wpos:+2
       
        For Local i:Int = 0 Until segs
                Local fang:Float = 180 + i * fstep
                xy[wpos] = (x + r) + Cos(fang) * r
                xy[wpos + 1] = (y + r) + Sin(fang) * r
                wpos:+2
        Next
               
        xy[wpos] = x + r
        xy[wpos + 1] = y
        wpos:+2
       
        ' rt corner
        xy[wpos] = x + width - r
        xy[wpos + 1] = y
        wpos:+2
               
        For Local i:Int = 0 Until segs
                Local fang:Float = 270 + i * fstep
                xy[wpos] = (x + width - r) + Cos(fang) * r
                xy[wpos + 1] = (y + r) + Sin(fang) * r
                wpos:+2
        Next
       
        xy[wpos] = x + width
        xy[wpos + 1] = y + r
        wpos:+2       
       
        ' rb corner
        xy[wpos] = x + width
        xy[wpos + 1] = y + height - r
        wpos:+2               
       
        For Local i:Int = 0 Until segs
                Local fang:Float = 0 + i * fstep
                xy[wpos] = (x + width - r) + Cos(fang) * r
                xy[wpos + 1] = (y + height - r) + Sin(fang) * r
                wpos:+2
        Next
       
        xy[wpos] = x + width - r
        xy[wpos + 1] = y + height
        wpos:+2               
       
        ' lb corner
        xy[wpos] = x + r
        xy[wpos + 1] = y + height
        wpos:+2
       
        For Local i:Int = 0 Until segs
                Local fang:Float = 90 + i * fstep
                xy[wpos] = (x + r) + Cos(fang) * r
                xy[wpos + 1] = (y + height - r) + Sin(fang) * r
                wpos:+2
        Next
       
        xy[wpos] = x
        xy[wpos + 1] = y + height - r
        wpos:+2               
               
        DrawPoly(xy)
EndFunction

Семпл в аттаче

dimanche13 06.12.2011 10:20

Ответ: Скруглённые уголки на BlitzMax
 
нда, ребятки.
нашли чем меряться) в наши дни мерялись не этим.
не вижу смысла махаться ненужными функциями, и выжимать из них лишние синусы
мир вам

Черный крыс 06.12.2011 13:59

Ответ: Скруглённые уголки на BlitzMax
 
Тама еще отрисовка будет черезжоперная - что тоже является тормозом, но это уже проблема офф-модулей.

Функция действительно бесполезная.
переделать ее на отрисовку линий - куда больше проку.

Randomize 06.12.2011 14:22

Ответ: Скруглённые уголки на BlitzMax
 
Цитата:

Сообщение от dimanche13 (Сообщение 212639)
нда, ребятки.
нашли чем меряться) в наши дни мерялись не этим.
не вижу смысла махаться ненужными функциями, и выжимать из них лишние синусы
мир вам

лучше ничего не делать и пусть гниёт забытый миром и без того пустой раздел blitzmax


Часовой пояс GMT +4, время: 00:46.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot