July 19, 2019, 03:39:19 AM

Author Topic: How to create fluid gradients?  (Read 329 times)

Offline Grisu

  • Jr. Member
  • **
  • Posts: 24
    • Pocket Radio Player
How to create fluid gradients?
« on: April 20, 2019, 12:24:20 PM »
Hello everyone,

I'm trying to create a gradient that moves through sets of certain colours fluently. Somehow I can't get it working. :(

Example Gif:


It only has to cover a 272x85 pixel canvas, so in theory, it should run on the fly even on low-end PCs.
On top it would be nice to have a different "theme" each time the app restarts. So it doesn't get boring too quickly.
For instance: alter the direction of the flow or change the basic colour pattern / darkness etc.

Below is a basic example framework:
Code: [Select]

SuperStrict

Framework MaxGui.Drivers
 Import BRL.GLMax2D
 Import BRL.StandardIO
 Import BRL.Pixmap
 Import BRL.EventQueue
 Import BRL.Timer
 Import BRL.Retro
 Import BRL.Max2D
 Import BRL.Pngloader
 Import BRL.Jpgloader

Const MAINWINDOW_W:Int = 278
Const MAINWINDOW_H:Int = 154
Const WIN_MENU_FLAG:Int = 0

Global SpectrumTimer:TTimer=CreateTimer(24) ' fixed!

Global icol:Float=0.5 'start value
Print "First icol value: "+icol

' Main Window
Global flags:Int=WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS | WINDOW_CENTER | WIN_MENU_FLAG | WINDOW_ACCEPTFILES | WINDOW_RESIZABLE
Global window:TGadget=CreateWindow("Rainbow Test",0,0,MAINWINDOW_W,MAINWINDOW_H+70,Null, flags)
Global Button1:TGadget=CreateButton("Generate Colour Variation",2,MAINWINDOW_H+70-45,MAINWINDOW_W-3,20,window,BUTTON_OK)
Global Button2:TGadget=CreateButton("Exit APP",2,MAINWINDOW_H+70-20,MAINWINDOW_W-3,20,window,BUTTON_OK)

Global RadioStationCanvas:TGadget = CreateCanvas(2, 2, 274, 87, window, PANEL_ACTIVE)

' Refresh Canvas = Blank
SetGraphics CanvasGraphics( RadioStationCanvas )
SetColor 0,0,0
Cls
Flip()

RndSeed()

' //////////////// Main Loop


While WaitEvent()
Select EventID()
Case EVENT_WINDOWCLOSE
End

Case EVENT_GADGETACTION
          Select EventSource()

                 Case BUTTON1
                      icol:Float=Rnd(0.5,8)
                      Print "New icol value: "+icol

                 Case BUTTON2
          End

                 End Select

       Case EVENT_TIMERTICK

    Select EventSource()

Case SpectrumTimer

        SetGraphics CanvasGraphics( RadioStationCanvas )
        Cls
        Draw_Rainbow(icol)
        Flip 0
         
       End Select

End Select
 
Wend
End


Function Draw_Rainbow(icol:Float)
' Refresh Rainbow Background
Local icol_tmp:Float=icol:Float 'pass data
Local y:Int=1

For y:Int=0 To 85
          SetColor (icol_tmp*32,icol_tmp*16,(128)+icol_tmp*2)
DrawLine 1, y, 272,y
icol_tmp:Float=icol_tmp+0.05
Next

End Function


Any help is appreciated.

Thanks!
Grisu
Pocket Radio Player     Cardwar

Offline Derron

  • Hero Member
  • *****
  • Posts: 2208
Re: How to create fluid gradients?
« Reply #1 on: April 20, 2019, 04:10:29 PM »
https://github.com/GWRon/Dig/blob/master/base.util.color.bmx

-> toHsl and fromHSL will help you.

Why? To have a rainbow you keep saturation and lightness constant and just change the hue value.


bye
Ron

Offline Derron

  • Hero Member
  • *****
  • Posts: 2208
Re: How to create fluid gradients?
« Reply #2 on: April 20, 2019, 04:27:39 PM »
Code: BlitzMax
  1. global startI:int = 0
  2. [...]
  3.  
  4. local c:TColor = new TColor.Create(255,0,0)
  5. For local i:int = 0 until 100
  6.         local h:Float = ((startI+i) mod 100) / 100.0
  7.         c.FromHSL(h, 0.5, 0.5).SetRGBA()
  8.         DrawLine(0,i,100,i)
  9. Next
  10. startI :+ 1
  11.  
  12. SetColor 255,255,255
  13.  


Attached image is non-repeatable and looses quality because of gif compression but with a "modulo" and staying within 0-1.0 of "hue" you should create a repeating pattern.

bye
Ron

Offline Grisu

  • Jr. Member
  • **
  • Posts: 24
    • Pocket Radio Player
Re: How to create fluid gradients?
« Reply #3 on: April 20, 2019, 06:37:31 PM »
Thanks for a lot your assistance Ron! I got the basic stuff working now.

Code: *requires: "base.util.color.bmx"*
Code: [Select]
' Test Rob's Test code
SuperStrict

Framework MaxGui.Drivers
 Import BRL.GLMax2D
 Import BRL.StandardIO
 Import BRL.Pixmap
 Import BRL.EventQueue
 Import BRL.Timer
 Import BRL.Retro
 Import BRL.Max2D
 Import BRL.Pngloader
 Import BRL.Jpgloader
 Import "base.util.color.bmx"

Const MAINWINDOW_W:Int = 278
Const MAINWINDOW_H:Int = 154
Const WIN_MENU_FLAG:Int = 0

Global SpectrumTimer:TTimer=CreateTimer(24) ' fixed!

Global startI:Int = 0 'Rob's
Global use_mode:Int = 0   

' Main Window
Global flags:Int=WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS | WINDOW_CENTER | WIN_MENU_FLAG | WINDOW_ACCEPTFILES | WINDOW_RESIZABLE
Global window:TGadget=CreateWindow("Test App",0,0,MAINWINDOW_W,MAINWINDOW_H+70,Null, flags)
Global Button1:TGadget=CreateButton("",2,MAINWINDOW_H+70-45,MAINWINDOW_W-3,20,window,BUTTON_OK)
SetGadgetText (Button1, "Switch Mode (Vert)")

Global Button2:TGadget=CreateButton("Exit APP",2,MAINWINDOW_H+70-20,MAINWINDOW_W-3,20,window,BUTTON_OK)
Global RadioStationCanvas:TGadget = CreateCanvas(2, 2, 274, 87, window, PANEL_ACTIVE)

' //////////////// Main Loop
While WaitEvent()
Select EventID()
Case EVENT_WINDOWCLOSE
End

Case EVENT_GADGETACTION
          Select EventSource()

                 Case BUTTON1
                      If use_mode:Int=0 Then
                        use_mode:Int=1
                        SetGadgetText (Button1, "Switch Mode (Horz)")
                      Else
                        use_mode:Int=0 ' switch between different modes!                   
                        SetGadgetText (Button1, "Switch Mode (Vert)")
                      EndIf 
                 Case BUTTON2
          End

                 End Select

       Case EVENT_TIMERTICK

    Select EventSource()

Case SpectrumTimer

        SetGraphics CanvasGraphics( RadioStationCanvas )
        Cls

        If use_mode=0 Then
          Draw_Rob_vert(startI:Int)
        Else
          Draw_Rob_horz(startI:Int)
        EndIf
        startI :+ 1

        Flip 0
         
       End Select

End Select
 
Wend
End

Function Draw_Rob_horz(startI:Int)
Local c:TColor = New TColor.Create(255,0,0)

For Local x:Int = 1 Until 273
        Local h:Float = ((startI+x) Mod 100) / 100.0
        c.FromHSL(h, 0.5, 0.5).SetRGBA()
        DrawLine(x,1,x,85)
Next
End Function

Function Draw_Rob_vert(startI:Int)
Local c:TColor = New TColor.Create(255,0,0)

For Local y:Int = 1 Until 86
        Local h:Float = ((startI+y) Mod 100) / 100.0
        c.FromHSL(h, 0.5, 0.5).SetRGBA()
        DrawLine(1,y,272,y)
Next
End Function

Apart from changing the scrolling directions as done in my code above.
Is there a way to change the existing rainbow color cycle to other "more crazy" color rotations?
I'd like to add some more (predefined if need be) variaty.

Grisu
Pocket Radio Player     Cardwar

Offline Derron

  • Hero Member
  • *****
  • Posts: 2208
Re: How to create fluid gradients?
« Reply #4 on: April 20, 2019, 07:27:27 PM »
Just play with the other params. Eg. You could climb the s-aturation or the l-ightness up and down instead of the h-ue.
Next to hsl I also have color functions for HSV ... might work too.


Limiting the values to not go from 0.0 to 1.0 means you could also have gradients with fewer colors..


Just look for color ramp algorithms there might pop up some (did not check it).

Bye
Ron

Offline Grisu

  • Jr. Member
  • **
  • Posts: 24
    • Pocket Radio Player
Re: How to create fluid gradients?
« Reply #5 on: April 20, 2019, 08:15:30 PM »
Thanks again. Will try to come up with something.
Pocket Radio Player     Cardwar

Offline Derron

  • Hero Member
  • *****
  • Posts: 2208
Re: How to create fluid gradients?
« Reply #6 on: April 20, 2019, 08:16:18 PM »
Code: BlitzMax
  1.  
  2.                 For local i:int = 0 until height
  3.                         local h:Float = ((startI+i) mod 100) / 100.0
  4.                         c.FromHSL(h, 0.5 + float(sin(Millisecs()/10)) * 0.4, 0.5).SetRGBA()
  5.                         DrawLine(120,i,220,i)
  6.                 Next
  7.  
  8.                 c = new TColor.Create(255,0,0)
  9.                 For local i:int = 0 until height
  10.                         local h:Float = (Max(0, ((startI+i)-50)) mod 100) / 100.0
  11.                         c.FromHSL(h, 0.5, float(0.5 + 0.5*sin(Millisecs()/10))).SetRGBA()
  12.                         DrawLine(240,i,340,i)
  13.                 Next
  14.  
  15.                 c = new TColor.Create(255,0,0)
  16.                 local scaleY:Float = float(10 + 50*sin(Millisecs()/10))
  17.                 For local i:int = 0 until height
  18.                         local h:Float = Min(1.0, (i + 50 + scaleY) / 100.0)
  19.                         c.FromHSL(0.5, h, 0.5).SetRGBA()
  20.                         DrawLine(360,i,460,i)
  21.                 Next
  22.                 SetColor 120,120,120
  23.                 For local i:int = 0 to 100
  24.                         DrawLine(360+i, 0, 360+i, 10 + 10 * float(Max(-10, Sin(Millisecs()/2 + 10*i))))
  25.  
  26.                         DrawLine(360+i, height - 10 + 10 * float(Max(-10, Sin(Millisecs()/2 + 10*i))),  360+i, height)
  27.                 Next
  28.                 SetColor 255,255,255
  29.  

Some more stuff (visual example:  see attachment).


As said just play with the colors - even the sinus wave thing could be again colored in a gradient or so.
Instead of the sinus wave you might draw random bubbles (white) on the pulsating background ... and much more.

bye
Ron

Offline Henri

  • Full Member
  • ***
  • Posts: 203
Re: How to create fluid gradients?
« Reply #7 on: April 21, 2019, 11:31:18 AM »
Hi,

just for the sake of posting something useless:

Code: BlitzMax
  1.  
  2. Strict
  3.  
  4. Graphics 640,480
  5.  
  6. CreatePlasma(200, 200)
  7.  
  8. Function CreatePlasma(width:Int, height:Int)
  9.  
  10.         Const PLASMA_INCREMENT:Float = 0.8
  11.         Const PLASMA_SPEED:Float = 1.0
  12.        
  13.         Local x:Int, y:Int, increment:Double = PLASMA_INCREMENT
  14.         Local base:Float = 50, base_r:Float = 50, base_g:Float = 50, base_b :Float= 50, sel:Int
  15.         Local dx:Double, dy:Double, dv:Double
  16.         Local t:Double, r:Int, g:Int, b:Int
  17.        
  18.         While Not KeyHit(KEY_ESCAPE)
  19.                
  20.                 t:+ PLASMA_SPEED
  21.                 Cls
  22.                
  23.                 For x = 0 Until width
  24.                         For y = 0 Until height
  25.                        
  26.                                 dx = x + .5 * Sin(t/5.0)
  27.                                 dy = y + .5 * Cos(t/3.0)
  28.                                 dv = Sin(x*10 + t) + Sin(10*(x*Sin(t/2.0) + y*Cos(t/3.0)) + t) + Sin(Sqr(100*(dx*dx + dy*dy)+1) + t)
  29.                                
  30.                                 r = 255 * Abs( Sin( dv * Pi )) + base_r
  31.                                 g = 255 * Abs( Sin( dv * Pi + 2 * Pi / 3 ))      + base_g
  32.                                 b = 255 * Abs( Sin( dv * Pi + 4 * Pi / 3 ))      + base_b
  33.                                
  34.                                 SetColor(r, g, b)
  35.                                 Plot(x, y)
  36.                         Next
  37.                 Next
  38.                
  39.                 Flip
  40.                 Delay 2
  41.                
  42.                 Select sel
  43.                 Case 0  base_r:+ increment; base = base_r
  44.                 Case 1  base_g:+ increment; base = base_g
  45.                 Case 2  base_b:+ increment; base = base_b
  46.                 EndSelect
  47.                
  48.                 If base > 190 Then increment = - PLASMA_INCREMENT
  49.                 If base < 40 And increment < 0 Then
  50.                         increment = PLASMA_INCREMENT
  51.                         sel:+ 1
  52.                         If sel > 2 Then sel = 0
  53.                 EndIf
  54.                
  55.         Wend
  56. EndFunction
  57.  
  58.  

-Henri 
- Got 01100011 problems, but the bit ain't 00000001

Offline imaginaryhuman

  • Jr. Member
  • **
  • Posts: 10
Re: How to create fluid gradients?
« Reply #8 on: April 23, 2019, 12:17:49 AM »
I would use a kind of indexed color with a palette. Render a grayscale gradient to a texture (offline once) with horizontal bars from top to bottom. Then to display it, use a given palette texture or array as a lookup. Look up the grayscale value (e.g. red byte from readpixel, or use alpha), grab the color, and output it in a simply y loop. you can add an offset to the lookup index and wrap it around with a modulo.

Offline Grisu

  • Jr. Member
  • **
  • Posts: 24
    • Pocket Radio Player
Re: How to create fluid gradients?
« Reply #9 on: May 05, 2019, 09:00:11 PM »
@Henri: That looks nice!

@all: Instead of using Derrons modules, I came up with something simpler that runs "out of the box"

Code: [Select]
SuperStrict

Framework MaxGui.Drivers
 Import BRL.GLMax2D
 Import BRL.StandardIO
' Import BRL.Pixmap
 Import BRL.EventQueue
 Import BRL.Timer
 Import BRL.Retro
 Import BRL.Max2D
' Import BRL.Pngloader
' Import BRL.Jpgloader

Const MAINWINDOW_W:Int = 278
Const MAINWINDOW_H:Int = 154
Const WIN_MENU_FLAG:Int = 0

Global SpectrumTimer:TTimer=CreateTimer(24) ' fixed!

' Main Window
Global flags:Int=WINDOW_TITLEBAR | WINDOW_CLIENTCOORDS | WINDOW_CENTER | WIN_MENU_FLAG | WINDOW_ACCEPTFILES | WINDOW_RESIZABLE
Global window:TGadget=CreateWindow("Testing...",0,0,MAINWINDOW_W,MAINWINDOW_H+70,Null, flags)
'Global Button1:TGadget=CreateButton("Generate Colour Variation",2,MAINWINDOW_H+70-45,MAINWINDOW_W-3,20,window,BUTTON_OK)
Global Button2:TGadget=CreateButton("Exit APP",2,MAINWINDOW_H+70-20,MAINWINDOW_W-3,20,window,BUTTON_OK)

Global RadioStationCanvas:TGadget = CreateCanvas(2, 2, 274, 87, window, PANEL_ACTIVE)

' / BG Globals
Global copperr:Float[85]
Global copperg:Float[85]
Global copperb:Float[85]

Global rsizeangle#=0, roffsetangle#=0, gsizeangle#=0
Global goffsetangle#=0, bsizeangle#=0, boffsetangle#=0
Global angle0step#=.3*4, angle1step#=.3*4, angle2step#=.03*4, angle3step#=.05*4, angle4step#=.12*4, angle5step#=.08*4

' //////////////// Main Loop
While WaitEvent()
Select EventID()
Case EVENT_WINDOWCLOSE
End

Case EVENT_GADGETACTION
          Select EventSource()

'                Case BUTTON1

                 Case BUTTON2
          End

                 End Select

       Case EVENT_TIMERTICK

    Select EventSource()

Case SpectrumTimer

        SetGraphics CanvasGraphics( RadioStationCanvas )
        Spec_Draw_Anim()                   
        Flip 0
         
       End Select

End Select
 
Wend
End ' of the world
       
' / First Background Layer
Function Spec_Draw_Anim()
Local  rsize#,roffset#         
Local  gsize#,goffset#         
Local  bsize#,boffset#         

    rsizeangle=(rsizeangle + angle0step) Mod 360
rsize#=(Sin(rsizeangle)*0.5) + 3.5
roffsetangle=(roffsetangle + angle1step) Mod 360
roffset#=(Sin(roffsetangle)*70) + 96

      gsizeangle=(gsizeangle + angle2step) Mod 360
gsize#=(Sin(gsizeangle)*0.5) + 3.5
goffsetangle=(goffsetangle + angle3step) Mod 360
goffset#=(Sin(goffsetangle)*70) + 96

bsizeangle=(bsizeangle + angle4step) Mod 360
bsize#=(Sin(bsizeangle)*0.5) + 3.5
boffsetangle=(boffsetangle + angle5step) Mod 360
boffset#=(Sin(boffsetangle)*70) + 96

For Local i:Int=1 To 85 'Step x
copperr[i]=( 70*Sin(((i + roffset) * rsize) Mod 360))+70
copperg[i]=( 70*Sin(((i + goffset) * gsize) Mod 360))+70
copperb[i]=( 70*Sin(((i + boffset) * bsize) Mod 360))+70
        SetColor(copperg[i],copperb[i],copperr[i])
DrawRect 1, i, 272, 1 
Next
End Function

I plan to add some foreground items. I need to make this more interesting with some moving objects / layers in the front.

What do you think? Ideas and opinions are welcome. :)
Pocket Radio Player     Cardwar