Page 1 of 2

Nova Attractor?

Posted: Fri May 08, 2009 7:08 am
by idle
Nova Attractor?

Creates super nova and plasma ball effects.
Not really sure if it's an attractor but it's a pretty weird function and it's very chaotic.

Image

updated added FFT to visualize sound

compiled version only sorry - as it's littered with comments!
Set Record to WaveOut mix and adjust level to suit
Will add code to do it automatically later.

[instructions]

Left Click Y value alters effect
M - Changes Mode
UP / Down - Speed and Forward or Rewind in Pause
Left / Right - Cycle effect
A / Z - Brightness
Space - Random Effect
P - Pause to explore function, UP and Down to change
D - Display
V - Visualize set record to waveout
S / X - Amplitude gain for visualization
R - Accumulator buffer to explore fx
E - Echo
1 / 2 less or more plots, space or click activates


http://www.idlearts.com/nova.exe

Code: Select all


;Nova Attactor Explorer copyright 2009 Andrew Ferguson Idlearts
;An idle curiosity, don't really know if it's really an attractor as such but what the heck!  
;You may use and modify the code as per GPL just including the credit of what it is called.
;IdleArts Nova Attractor 

;left click to generate effects the Y val alters the seed. 
;P to pause then Up down Arrow to go forward and Backwards it time 
;Up / Down changes evolution speed larger the value the faster the bang
;Left / Right cycles through Effect 
;M changes mode Circle Vertical Horizontal  

Structure star
   color.i
   speed.f
   x.f
   y.f
   z.f
EndStructure

Global NewList stars.star()
Global pt.point
Global ef.f
Global speed.f
Global Dim accum.f(2048*2048)
Global mode, pmode, gain.f,gpause,gDisplay  
Global scx,scy,width,height  
Global lmut = CreateMutex()

Procedure drawStars(hdc)

Protected *px.long,dx.d,dy.d,mx.f,px,py,rt.f
Static ct, sx.f, sy.f,sz.f, tlspeed 


Pitch  = DrawingBufferPitch()
       
     
  ForEach Stars()
    If pmode  
      dx = stars()\x * #PI   
      dy = stars()\y    
    Else 
      dx = stars()\x  
      dy = stars()\y  
    EndIf 
         
     
    dz = Sqr(dx*dx+dy*dy) 
    mx = stars()\speed * speed * dz
         
    If mode = 1
      px = Int(scx + Tan((Sin(dx) + Cos(dy))) * mx)
      py = Int(scy + (Cos(dx) - Sin(dy)) * mx)
    ElseIf mode=2
      px = scx + (Sin(dx) + Cos(dy)) * mx
      py = scy + Tan(Cos(dx) - Sin(dy)) * mx
    Else 
      px = Int(scx + (Sin(dx) + Cos(dy)) * mx)  
      py = Int(scy + (Cos(dx) - Sin(dy)) * mx)  
    EndIf 
    
    If gpause 
      If tlspeed = 0 
         tlspeed = speed 
      EndIf 
      stars()\x + (px/ef) 
      stars()\y + (py/ef) 
      stars()\speed - 0.00001
            
    Else 
       If tlspeed  
        speed = tlspeed 
        tlspeed = 0
       EndIf        
      stars()\x + (px/ef) 
      stars()\y + (py/ef) 
      stars()\speed + 1/dz    
    EndIf 
       
         
    If px >= 1 And py >= 1 And px < width-1 And py < height-1
       
       ofx1 = px + (py * width)
       accum(ofx1) + gain 
       nx = px-1
       While nx < px+1
         ny = py-1
         While ny < py+1 
           ofx = nx + (ny * width)
           rt + accum(ofx)
           ny+1
         Wend   
         nx+1
       Wend     
       col = (gain * rt) * 155    
       offset = (px*4 + (py * pitch))
       *px = hdc + offset
       *px\l = RGB(col,col*0.2,col*0.4)
       
       rt=0
       
    EndIf
     
  Next
  
  Delay(20)

EndProcedure

Procedure draw(*void)
  
  Static lg.f, lspeed.f,lef.f 
  ef=100.0
  speed = 3.25
  gain = 0.11 
  lg =gain
  lef = ef
  lspeed = speed 
  lmode = mode  
  
  While 1 
    
    LockMutex(lmut)
          
    StartDrawing(ScreenOutput())

    If gpause 
       DrawText(20,0,"Paused",RGB(255,0,0),RGB(0,0,0))
    EndIf 
    hdc= DrawingBuffer()
    DrawStars(hdc)
    If gDisplay 
      DrawText(20,20,"Gain " + StrF(gain,3),RGB(0,255,0),RGB(0,0,0))
      DrawText(20,40,"Distance " + StrF(speed,4),RGB(0,255,0),RGB(0,0,0)) 
      DrawText(20,60,"Effect " + StrF(ef,3),RGB(0,255,0),RGB(0,0,0))
    EndIf   
    StopDrawing()
    FlipBuffers()
    ClearScreen(RGB(0,0,0))
    ZeroMemory_(@accum(),width*height*4)
    
    UnlockMutex(lmut)
     
  Wend

EndProcedure

InitSprite()

s$ ="IdleArts Nova Attractor Explorer Copyright Andrew Ferguson 2009"
OpenWindow(0,0,0,800,600,s$,#PB_Window_SizeGadget | #PB_Window_SystemMenu | #PB_Window_MinimizeGadget |#PB_Window_MaximizeGadget | #PB_Window_ScreenCentered)
If CreateMenu(0, WindowID(0))  
     MenuTitle("Help")
     MenuItem(2, "Instructions")
     MenuItem(1, "IdleArts")
EndIf

OpenWindowedScreen(WindowID(0),0,0,800,600,0,0,0)

width = 800
height = 600
scx=400
scy=300
cid = 0 

ClearScreen(RGB(0, 0, 0))

RandomSeed(timeGetTime_())

For a = 0 To 50000
  AddElement(stars())
  stars()\x = Random(800)
  stars()\y = Random(800)
  stars()\color = RGB(Random(190)+64,62,0)
  stars()\speed = 1/Sqr(stars()\x*stars()\x + stars()\y*stars()\y)
Next
 

Repeat

 event = WaitWindowEvent()
 
 Select event  
 Case #WM_LBUTTONDOWN
    PauseThread(ts)
    ForEach stars()
      stars()\x = Random(1600) - 800
      stars()\y = Random(1600) - 800 
      stars()\color = stars()\color = RGB(Random(190)+64,62,0)
      stars()\speed = 1/Sqr(stars()\x*stars()\x + stars()\y*stars()\y)
    Next
   
    ZeroMemory_(@accum(),width*height*4) 
           
    GetCursorPos_(@pt)
    ef = ((-180-180) / (1-height) * pt\y)  - 270
    ResumeThread(ts)
 Case  #WM_RBUTTONDOWN
    GetCursorPos_(@pt)
 Case #WM_SIZE
           
    width = WindowWidth(0)
    height = WindowHeight(0)
    scx = width/2
    scy= height/2
    If IsThread(ts) 
       LockMutex(lmut)
       PauseThread(ts)
       If width > 0
         CloseScreen()
         OpenWindowedScreen(WindowID(0),0,0,width,height,1,0,0)
        EndIf 
       UnlockMutex(lmut)
       ResumeThread(ts)
    Else 
       ts = CreateThread(@draw(),#Null)
    EndIf  
 Case #PB_Event_Menu
     ev = EventMenu()  
     If ev = 1 
         RunProgram("http:/www.idlearts.com/nova.html")
        
     ElseIf ev = 2   
     st.s = "IdleArts Nova Attractor Explorer v0.3" + #CRLF$ + #CRLF$
     st + "Left Click the x,y alters effect" + #CRLF$ 
     st + "M - Changes Mode" + #CRLF$
     st + "UP / Down - Speed and Forward or Rewind in Pause" + #CRLF$
     st + "Left / Right - Effect " + #CRLF$
     st + "A / Z - Brightness "  + #CRLF$
     st + "Space - Random Effect" + #CRLF$
     st + "P - Pause to explore a function UP and Down to change" + #CRLF$
     st + "D - Display" 
        MessageRequester("Idlearts Nova Attractor",st)
     EndIf 
 EndSelect
  
 
 If GetAsyncKeyState_(#VK_DOWN) & 1
       
       If speed > 1 
          speed + 0.1  
       ElseIf speed < 1 And speed > 0.1 
          speed + 0.001
       Else 
          speed + 0.0001
       EndIf 
             
 ElseIf GetAsyncKeyState_(#VK_UP) & 1
       
       If Abs(speed) > 1 
          speed - 0.1  
       ElseIf Abs(speed) < 1 And Abs(speed) > 0.1 
          speed - 0.001
       Else 
          speed - 0.0001
       EndIf 
 ElseIf GetAsyncKeyState_(#VK_D) & 1
       gDisplay ~ gDisplay
 ElseIf GetAsyncKeyState_(#VK_P) & 1
       gpause ~ gpause 
 ElseIf GetAsyncKeyState_(#VK_M) & 1
    mode + 1 
    If mode > 2 
      mode=0
    EndIf 
 ElseIf GetAsyncKeyState_(#VK_O) & 1
    pmode ~ pmode   
 ElseIf GetAsyncKeyState_(#VK_A) & 1
    gain + 0.01
 ElseIf GetAsyncKeyState_(#VK_Z) & 1
    gain - 0.01
 ElseIf GetAsyncKeyState_(#VK_RIGHT) & 1
     ef + 0.01
 ElseIf GetAsyncKeyState_(#VK_LEFT) & 1
     ef - 0.01        
 ElseIf GetAsyncKeyState_(#VK_SPACE) & 1
    PauseThread(ts)
    ForEach stars()
      stars()\x = Random(1600) - 800
      stars()\y = Random(1600) - 800 
      stars()\color = RGB(Random(190)+64,62,0)
      stars()\speed = 1/Sqr(stars()\x*stars()\x + stars()\y*stars()\y)
    Next
   
    ZeroMemory_(@accum(),width*height*4) 
           
    GetCursorPos_(@pt)
    ef = Random(360)-180 
    ResumeThread(ts)
 
 EndIf      
   
Until event = #WM_CLOSE 

Posted: Fri May 08, 2009 8:54 am
by Hurga
Hi idle

After a short time of running i got an "Array index out of bound"error in this line...

Code: Select all

accum(ct,offset) = stars()\color 

Posted: Fri May 08, 2009 10:21 am
by idle
I didn't run it with the debugger on, is to slow, removed the accumulator array.

Posted: Fri May 08, 2009 12:00 pm
by Kaeru Gaman
> removed the accumulator array.

oh... I'd be interested in seeing the accum, too...
ermn... would you post it again, pse?


cool effect... got to analyse the whole thingy...

uncommon approach, start/stop drawing and flipbuffers in a thread...

Posted: Fri May 08, 2009 10:20 pm
by idle
It doesn't really work any better with an accumulator, maybe I'm not doing it right.

[edited code at first post]

Posted: Sat May 09, 2009 2:11 am
by Kaeru Gaman
thnx!

interesting thingy.

Posted: Sat May 09, 2009 3:50 am
by idle
I kind of surprised myself, the only question is how best to render it.
Interpolation? sprites / particle engine?

Seems to be a bit better averaging with a counter and scaling the color based on that.

Posted: Sat May 09, 2009 10:31 am
by milan1612
Wow! That looks amazing! :)

Posted: Sat May 09, 2009 10:40 am
by djes
Really, really nice!

Trying to do my own ClearScreen(), I noticed that you can remove it :)

Try this (floats)

Code: Select all

;Nova Generator
;An idle curiosity, I'm sure it could be abstacted to makes some really cool FX

;left mouse click re seeds
;right mouse click modifies
; +/- changes speed (like zoom in out forward rewind)
; m change mode
Structure star
   color.i
   speed.f
   x.f
   y.f
EndStructure

Global NewList stars.star()
Global pt.point
Global ef.f
Global speed.f
Global Dim accum.f(800*600)
Global mode
 
Procedure drawStars(hdc)

Protected *px.long,dx.f,dy.f,mx.f,px,py,rt.f
Static ct

Pitch  = DrawingBufferPitch()
       
  ox = pt\x
  oy = pt\y
   
  ForEach Stars()
    dx = ox - stars()\x
    dy = oy - stars()\y
    dz = Sqr(dx*dx+dy*dy)
    mx = stars()\speed * dz * speed
    If mode = 1
      px = 400 + Tan((Sin(dx) + Cos(dy))) * mx
      py = 300 + (Cos(dx) - Sin(dy)) * mx
    ElseIf mode=2
      px = 400 + (Sin(dx) + Cos(dy)) * mx
      py = 300 + Tan(Cos(dx) - Sin(dy)) * mx
    Else
      px = 400 + (Sin(dx) + Cos(dy)) * mx
      py = 300 + (Cos(dx) - Sin(dy)) * mx
    EndIf
    stars()\x + px/ef
    stars()\y + py/ef 
    stars()\speed + 1/Sqr(dx*dx+dy*dy)     
         
    If px >= 1 And py >= 1 And px < 800-1 And py < 600-1
       
       ofx1 = px + (py * 800)
       accum(ofx1) + 0.1
       nx = px-1
       While nx < px+1
         ny = py-1
         While ny < py+1
           ofx = nx + (ny * 800)
           rt + accum(ofx)
           ny+1
         Wend   
         nx+1
       Wend     
       col = (0.11 * rt) * 255   
       offset = (px*4 + (py * pitch))
       *px = hdc + offset
       *px\l = RGB(col,col*0.2,col*0.4)
       
       rt=0
       
    EndIf
     
  Next

 
  Delay(0)

EndProcedure

Procedure MyZeroMemory(*ptr.float, length)

  length/4
  
  For u = 1 To length

    col.f = *ptr\f * 0.95
    *ptr\f = col
    *ptr + 4

  Next u

EndProcedure

Procedure draw(*void)
 
  ef=100
  speed = 1.25
  While 1
   
    StartDrawing(ScreenOutput())
    hdc= DrawingBuffer()
    DrawStars(hdc)
    StopDrawing()
    FlipBuffers()
    ;ClearScreen(RGB(0,0,0))
;    ZeroMemory_(@accum(),800*600*4)
    MyZeroMemory(@accum(),800*600*4)
  Wend

EndProcedure

InitSprite()
OpenWindow(0,0,0,800,600,"IdleArts Nova Generator - left click reseed mouse y axis for efx , m for mode, right click modify, +/- zoom")
OpenWindowedScreen(WindowID(0),0,0,800,600,0,0,0)



RandomSeed(timeGetTime_())

For a = 0 To 50000
  AddElement(stars())
  stars()\x = Random(800)
  stars()\y = Random(800)
  stars()\color = RGB(Random(190)+64,62,0)
  stars()\speed = 1/Sqr(stars()\x*stars()\x + stars()\y*stars()\y)
Next
 
ts = CreateThread(@draw(),#Null)

Repeat

 event = WaitWindowEvent()
 
 If event = #WM_LBUTTONDOWN
    PauseThread(ts)
    ForEach stars()
      stars()\x = Random(800)
      stars()\y = Random(800)
      stars()\color = stars()\color = RGB(Random(190)+64,62,0)
      stars()\speed = 1/Sqr(stars()\x*stars()\x + stars()\y*stars()\y)
    Next
   
    ZeroMemory_(@accum(),800*600*4)
           
    GetCursorPos_(@pt)
    ef = (pt\y - 300) 
    ResumeThread(ts)
 ElseIf event = #WM_RBUTTONDOWN
    GetCursorPos_(@pt)
 ElseIf event = #WM_KEYUP
     
    bt=0
 EndIf
 
 
 If GetAsyncKeyState_(#VK_SUBTRACT)
    If bt = 0
       bt = GetTickCount_()
    EndIf
       et = GetTickCount_() - bt
       speed - (et/1000000)
    ElseIf GetAsyncKeyState_(#VK_ADD)
      If bt = 0
       bt = GetTickCount_()
    EndIf
       et = GetTickCount_() - bt
       speed + (et/1000000)
    ElseIf GetAsyncKeyState_(#VK_M)
    mode + 1
    If mode > 2
      mode=0
    EndIf
 EndIf     
   
Until event = #WM_CLOSE 

Posted: Sat May 09, 2009 11:49 am
by idle
The float make it so much smoother. :D

Posted: Sat May 09, 2009 4:30 pm
by djes
I love this code!

Code: Select all

;Nova Generator
;An idle curiosity, I'm sure it could be abstacted to makes some really cool FX

;left mouse click re seeds
;right mouse click modifies
; +/- changes speed (like zoom in out forward rewind)
; m change mode
Structure star
   color.i
   speed.f
   x.f
   y.f
EndStructure

Global NewList stars.star()
Global pt.point
Global ef.f
Global speed.f
Global Dim accum.f(2048*2048)
Global mode
Global scx,scy,width,height 
Procedure drawStars(hdc)

Protected *px.long,dx.f,dy.f,mx.f,px,py,rt.f
Static ct

Pitch  = DrawingBufferPitch()
       
  ox = pt\x
  oy = pt\y
   
  ForEach Stars()
    dx = ox - stars()\x
    dy = oy - stars()\y
    dz = Sqr(dx*dx+dy*dy)
    mx = stars()\speed * dz * speed
    If mode = 1
      px = scx + Tan((Sin(dx) + Cos(dy))) * mx
      py = scy + (Cos(dx) - Sin(dy)) * mx
    ElseIf mode=2
      px = scx + (Sin(dx) + Cos(dy)) * mx
      py = scy + Tan(Cos(dx) - Sin(dy)) * mx
    Else
      px = scx + (Sin(dx) + Cos(dy)) * mx
      py = scy + (Cos(dx) - Sin(dy)) * mx
    EndIf
    stars()\x + px/ef
    stars()\y + py/ef 
    stars()\speed + 1/Sqr(dx*dx+dy*dy)     
         
    If px >= 1 And py >= 1 And px < width-1 And py < height-1
       
       ofx1 = px + (py * width)
       accum(ofx1) + 0.23
       nx = px-1
       While nx < px+1
         ny = py-1
         While ny < py+1
           ofx = nx + (ny * width)
           rt + accum(ofx)
           ny+1
         Wend   
         nx+1
       Wend     
       col = (0.11 * rt) * 255   
       offset = (px*4 + (py * pitch))
       *px = hdc + offset
       *px\l = RGB(col,col*0.2,col*0.4)
       
       rt=0
       
    EndIf
     
  Next
 
  Delay(0)

EndProcedure

Procedure MyZeroMemory(*ptr.float, length)

  length/4
  
  For u = 1 To length

    *ptr\f * 0.75
    *ptr + 4

  Next u

EndProcedure

Procedure draw(*void)
 
  ef=100
  speed = 5.25
  While 1
       
    StartDrawing(ScreenOutput())
    hdc= DrawingBuffer()
    DrawStars(hdc)
    StopDrawing()
    FlipBuffers()
    ;ClearScreen(RGB(0,0,0))
;    ZeroMemory_(@accum(),width*height*4)
    MyZeroMemory(@accum(),width*height*4)
  Wend

EndProcedure

InitSprite()

s$ ="IdleArts Nova Explorer"
OpenWindow(0,0,0,800,600,s$,#PB_Window_SizeGadget | #PB_Window_SystemMenu | #PB_Window_MinimizeGadget |#PB_Window_MaximizeGadget | #PB_Window_ScreenCentered)
If CreateMenu(0, WindowID(0))  ; here the menu creating starts....
     MenuTitle("About")
     MenuItem(1, "about")
EndIf


OpenWindowedScreen(WindowID(0),0,0,800,600,1,0,0)

width = 800
height = 600
scx=400
scy=300
ClearScreen(RGB(0, 0, 0))

RandomSeed(timeGetTime_())

For a = 0 To 50000
  AddElement(stars())
  stars()\x = Random(800)
  stars()\y = Random(800)
  stars()\color = RGB(Random(190)+64,62,0)
  stars()\speed = 1/Sqr(stars()\x*stars()\x + stars()\y*stars()\y)
Next

 
;ts = CreateThread(@draw(),#Null)

Repeat

 event = WaitWindowEvent()
 
 If event = #WM_LBUTTONDOWN
    PauseThread(ts)
    ForEach stars()
      stars()\x = Random(800)
      stars()\y = Random(800)
      stars()\color = stars()\color = RGB(Random(190)+64,62,0)
      stars()\speed = 1/Sqr(stars()\x*stars()\x + stars()\y*stars()\y)
    Next
   
    ZeroMemory_(@accum(),width*height*4)
           
    GetCursorPos_(@pt)
    ef = (pt\y - 300) 
    ResumeThread(ts)
 ElseIf event = #WM_RBUTTONDOWN
    GetCursorPos_(@pt)
 ElseIf event = #WM_KEYUP
    bt=0
 ElseIf event = #WM_SIZE
   
    width = WindowWidth(0)
    height = WindowHeight(0)
    scx = width/2
    scy= height/2
    If IsThread(ts)
       PauseThread(ts)
       If width > 0
         CloseScreen()
         OpenWindowedScreen(WindowID(0),0,0,width,height,1,0,0)
        EndIf
        ResumeThread(ts)
    Else
       ts = CreateThread(@draw(),#Null)
    EndIf 
 ElseIf event =#PB_Event_Menu
     ev = EventMenu() 
     st.s = "IdleArts Nova Explorer" + #CRLF$ + #CRLF$ + "Left Click - Mouse x,y alters effect" + #CRLF$
     st + "Right Click - Modifies current effect" + #CRLF$
     st + "M - Changes mode" + #CRLF$
     st + "+/- keys on keypad zoom in out exponential time" 
     If ev = 1
       MessageRequester("Idlearts Nova",st)
     EndIf
 EndIf
 
 
 If GetAsyncKeyState_(#VK_SUBTRACT)
    If bt = 0
       bt = GetTickCount_()
    EndIf
       et = GetTickCount_() - bt
       speed + (et/1000000)
    ElseIf GetAsyncKeyState_(#VK_ADD)
      If bt = 0
       bt = GetTickCount_()
    EndIf
       et = GetTickCount_() - bt
       speed - (et/1000000)
    ElseIf GetAsyncKeyState_(#VK_M)
    mode + 1
    If mode > 2
      mode=0
    EndIf
 EndIf     
   
Until event = #WM_CLOSE 

Posted: Sat May 09, 2009 4:34 pm
by Kaeru Gaman
perhaps it would be faster with tiny Sprite3D?
what is the smallest you can create a Sprite3D? 4x4pix?
even a 3x3 2D Sprite should be faster than plotting...
Drawing is always the slowest access...


@djes:

your versions are both slideshows. cruel.

Posted: Sat May 09, 2009 4:39 pm
by djes
Kaeru Gaman wrote:perhaps it would be faster with tiny Sprite3D?
what is the smallest you can create a Sprite3D? 4x4pix?
even a 3x3 2D Sprite should be faster than plotting...
Drawing is always the slowest access...


@djes:

your versions are both slideshows. cruel.
Try it without debugger...

Posted: Sat May 09, 2009 4:44 pm
by Kaeru Gaman
oops... :lol:

ok.. much better.

... but I don't like the color-effect it has, looks like a radiowave-foto.

Posted: Sat May 09, 2009 10:18 pm
by idle
@djes:

I'm still a bit confused why it works quite the way it does. I was trying to make an imploding star that would explode then suck back in on itself but got more than I expected.

Yes that accumulator works much better.
Have you tried to zoom in, you have to hold the key for awhile before it zooms.

@Kaeru

I don't know if sprites would make it faster part of me thinks yes the other no? It'll be easy enough to try though.

I also noticed that it's missing out scan lines, it's really noticeable on my good monitor but not on my regular one.