[GDI+][Class] Particle System 2.0

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

[GDI+][Class] Particle System 2.0

04 Jan 2017, 16:43

Particle System
v2.0
Download (github) | Images

Image

Intro:
Ever wanted to have pretty dots or lines or fancy things follow your mouse? Are you making a game using AHK and GDI+ and want to add some pizzazz? Or are you just bored? Well, now you can make some really cool/pretty/fancy stuff to do so!
Using the latest in high-tech cutting edge scientific technology, you can now create particles (often seen in games as fire, dust, little firefly type dots around a laser beam, or the mouse tail on windows OS) onto your screen or onto a GUI (or even your own GDI+ graphics), with AHK! Create fire, arcs, triangles, circles, helixs (helii?), dots, lines, text, spirals, fish, and more. It'll be fun and mesmerizing.

Description:
A simple class to add particles to your GUI or onto your screen, using GDI+ .

Features:
  • Styles: Generic, Generic Fill, Sparks, AllLines, Text, Image, Cursor
    Options: Many options including, but not limited to:
    • Jitter
    • color modes such as: cycle, random, life, life (reversed)
    • enter in multiple values to (try to) smoothly transition between all of them. like: 5 10 5 ... or ... 255, 100, 55, 0
    • delta-time
    • "on screen" drawing and "bitmap" drawing (draw on a gui)
    • jitter
    • gravity
    • ... much more ...
    3 simple demos are provided, as is a GUI which showcases all the features (but as usual, coding stuff yourself is more flexible)
    Documentation
    hardcoded Comic Sans MS just to make people annoyed
KNOWN LIMITATIONS:
  • * When using "mouse mode" (if you leave drawOnThis blank), Text and Image mode don't work
    * When using "non-mouse mode" (if you tell drawOnThis what to draw on), Cursor doesn't work
    * using the type "Cursor" can also sometimes prevent clicking.
    * When resizing the Preview in GUI-Toy, depending on how much lag you cause, your OS might pseudo-freeze. to fix this, alt-tab into another window or open up another window, such as taskmanage. it should resume to normal.
    * Life (reverse) color mode is weird. the first item misbehaves.
    * GUI-Toy is only setup to work on your primary monitor
    * CPU usage can reach 10-20% easily, it can be lowered a bit, but that's for you, the dev, to implement into your program (such as when idle, stop the sim+don't draw stuff, or decrease the FPS)
    * (Is this a limit?) it can smoothly display around 50-150 particles onscreen, based on your pc, at up to 60 FPS (possibly faster with QPC instead of loop or settimer)
Any help on the first 2 limitations would be appreciated.

Changelog:
Spoiler
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [GDI+][Class] Particle System 2.0

04 Jan 2017, 19:29

tidbit wrote:Ever wanted to have pretty dots or lines or fancy things follow your mouse?
I never did, but now I do :bravo:
Image
iPhilip
Posts: 796
Joined: 02 Oct 2013, 12:21

Re: [GDI+][Class] Particle System 2.0

04 Jan 2017, 19:56

Amazing and beautiful! :)

The demo1_Draw_Over_Buttons.ahk file is missing the following line at the bottom:

Code: Select all

#include %A_ScriptDir%\Gdip.ahk
Cheers!
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

Re: [GDI+][Class] Particle System 2.0

06 Jan 2017, 10:46

Helgef wrote:...
That's awesome :shock: now make in with "Generic Fill" or "AllLines"
iPhilip wrote:...
Whoops. I always forget #includes of stuff that are in my Lib. There really needs to be a standard one with a bunch of common things

Thanks guest3456!
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
SirRFI
Posts: 404
Joined: 25 Nov 2015, 16:52

Re: [GDI+][Class] Particle System 2.0

06 Jan 2017, 14:57

So, for fun script turned into an actual public release project. Truly impressive!
Use

Code: Select all

[/c] forum tag to share your code.
Click on [b]✔[/b] ([b][i]Accept this answer[/i][/b]) on top-right part of the post if it has answered your question / solved your problem.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [GDI+][Class] Particle System 2.0

07 Jan 2017, 06:32

tidbit wrote: now make in with "Generic Fill"
Image
User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

Re: [GDI+][Class] Particle System 2.0

08 Jan 2017, 14:52

Helgef: Beautiful :)
SirRFI: Thanks!
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
sGuest

Re: [GDI+][Class] Particle System 2.0

10 Jan 2017, 07:23

Hey tidbit :wave: I'd love to see the code for the example images you provided.
Very nice work by the way ! This adds top notch eye candy to windows. Can't wait for more of it 8-)
& I already have some great ideas to use it for :beer: Thanks :bravo:
User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

Re: [GDI+][Class] Particle System 2.0

10 Jan 2017, 12:00

sGuest wrote:Hey tidbit :wave: I'd love to see the code for the example images you provided.
Very nice work by the way ! This adds top notch eye candy to windows. Can't wait for more of it 8-)
& I already have some great ideas to use it for :beer: Thanks :bravo:
most of those images are from my old personal versions which no longer exist.

but here's a couple re-created in the gui-toy:
for image 6, plug in these values (Directions has a dropdown list of presets):
Image

for image 2, plug in these values:
Image

#4, fire, is made out of 3 emitters:
red/orange main fire,
white/yellow fire at the base where it's hottest
smoke
powered by negative gravity (like, -200 or so) and Spiral (can't remember, less than 180)

#3, fish, is 2 emitters.
blue sine wave with color variations as the water
the fish which are blue->yellow particles, spiraling about 180 degrees
to determine where the fish should jump out of, I access psys.particles[1] (see demo1 for multiple emitters) which returns an array of all particles of the water and their properties. So I choose a particle randomly on the last 50% of the water and create the fish at the x1/y1 of the chosen particle
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
sGuest

Re: [GDI+][Class] Particle System 2.0

10 Jan 2017, 15:12

Fantastic stuff to be creative with! :clap:
Thanks again :xmas:
User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

Re: [GDI+][Class] Particle System 2.0

12 Jan 2017, 12:38

Not really an update, update:
I tried as MasonJar13 suggested: https://github.com/acorns/Particle-Syst ... -271739881
It was nice, but only in certain situations (depends on what effect you want). I prefer how I originally intended for it to work. If what he explains does get added, it'd have to be as another option and not change what currently exist.

for me, and what I want/implemented: it takes the current mouse x/y + previous mouse x/y and gets the angle. that is then the direction still fill move.
as opposed to: "where the mouse is on screen based on placement of where the particles are being created." (mouse x/y and an anchor x/y)
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [GDI+][Class] Particle System 2.0

16 Jan 2017, 06:44

I did a function for making an image into a set of particles, it is quite primitive and I havn't really explored how to set up the properties of the emitter, eg, life span gravity etc...
Suggestions are welcome,

Code: Select all

; Usage Example
sFile:="57.jpg" ; tidbits avatar
I:=particliseImage(sFile,10,3,3)
showParticleIm(I)

particliseImage(file,size:="",space:=2,res:=4)
{	
	if !size
		size:=space*res*2
	psys:=new particles(30)
	pBitmap:=Gdip_CreateBitmapFromFile(file)
	if !pBitmap
	{
		MsgBox, Fail
		return -1
	}
	hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
	Gdip_GetDimensions(pBitmap,w,h)

	gui, new, +hwndguiId +ToolWindow
	gui, % guiId ":margin", 0,0
	gui, % guiId ":add", picture, % "x0 y0 " "w" w*space " h" h*space " 0xE hwndhPic"
	;gui, % guiId ":add", picture, , % "HBITMAP:" hBitmap ; debug
	psys.setCanvas(0, 0, w*space, h*space, 1, hPic)
	ctr:=0
	e:=psys.addEmitter()
	e.speed:=[]
	e.life:=[]
	e.color:=[]
	e.alpha:=[]
	e.circleSize:=[]
	e.pattern:=[]
	e.gravity:=[]
	e.coords:=[]
	Loop, % w//res
	{
		i:=A_Index
		x:=(i-1)*res
		Loop, % h//res
		{
			j:=A_Index
			y:=(j-1)*res
			argb := Gdip_GetPixel(pBitmap, x, y)
			rgb:=argb & 0x00FFFFFF
			e.color.Push(format("{:06x}",rgb ))
			e.alpha.Push(argb>>24)
			e.life.Push(1)
			e.speed.Push(0)
			e.circleSize.Push(size)
			e.pattern.Push(0)
			e.gravity.Push(0)
			e.coords.Push({x:x*space,y:y*space})
		}
	}
	return {psys:psys, w:w//res, h:h//res, guiId:guiId, hPic:hPic, res:res, space:space, size:size}
}

showParticleIm(pIm)
{
	pIm.psys.clear()
	pIm.psys.particles:=[]
	e:=pIm.psys.emitters[1]
	for k, tuple in e.coords
		pIm.psys.addParticle(tuple.x,tuple.y)
	for k, particle in pIm.psys.Particles[1]
		particle.life:=1
	!WinExist("ahk_id " pIm.guiId)
		Gui, % pIm.guiId ":show"
	pIm.psys.draw(pIm.hPic)
	return
}
pTidbit.png
pTidbit.png (54.74 KiB) Viewed 8602 times
For this, I didn't use the built in physics, i just moved the particles manually. I'll submit the code later when I remove some debug stuff.
2017-01-16_12-39-26.gif
2017-01-16_12-39-26.gif (868.61 KiB) Viewed 8602 times
SpecialG

Re: [GDI+][Class] Particle System 2.0

16 Jan 2017, 10:18

Great stuff lol - If I have some time I'll fiddle around with it

It would be nice to make the initial script work on the full set of screens. (aka multi monitor support)
I tried a few things but to no avail for the time being..
User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

Re: [GDI+][Class] Particle System 2.0

16 Jan 2017, 13:01

That is amazing Helgef o_o especially the second image.
I tried to make it one of those fancy "dots further away from mouse get smaller" things but kinda failed. can only figure out how to get the one under the cursor (it is flickery, unfortunately. not sure how to make ahk work with 400+ things nicely):
Image

as for optimizing it, see the comments with "!!!"

Code: Select all

; https://autohotkey.com/boards/viewtopic.php?p=126261#p126261
; Usage Example
#singleInstance, force
#persistent

; !!! improves speed A LOT
setBatchLines, -1

pToken:=Gdip_Startup()

sFile:=A_ScriptDir "\owl - small.jpg" ; tidbits avatar
I:=particliseImage(sFile,20,3,7)
showParticleIm(I)
settimer, effects, 200
return


effects:
	coordMode, mouse, client
	mouseGetPos, mx, my
	for k, v in psys.particles[1]
		if ((v.x1-(size//2)<=mx && v.x1+(size//2)>=mx) && (v.y1-(size//2)<=my && v.y1+(size//2)>=my))
		{
			dot:=k
			break
		}
	
	if (dot=dotp)
		return
		
	I:=particliseImage(sFile,20,3,7)
	I.psys.particles[1, dot].radius*=3
	showParticleIm(I)
	dotp:=dot
return

guiClose:
guiEscape:
esc::
	Gdip_Shutdown(pToken)
	exitapp
return




particliseImage(file,size:="",space:=2,res:=4)
{	
	if !size
		size:=space*res*2
	psys:=new particles(30)
	pBitmap:=Gdip_CreateBitmapFromFile(file)
	if !pBitmap
	{
		MsgBox, Fail
		return -1
	}
	hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
	Gdip_GetDimensions(pBitmap,w,h)

	gui, new, +hwndguiId +ToolWindow
	gui, % guiId ":margin", 0,0
	gui, % guiId ":add", picture, % "x0 y0 " "w" w*space " h" h*space " 0xE hwndhPic"
	;gui, % guiId ":add", picture, , % "HBITMAP:" hBitmap ; debug
	psys.setCanvas(0, 0, w*space, h*space, 1, hPic)
	ctr:=0
	e:=psys.addEmitter()

	; !!! you don't need to define all the blanks
	; e.speed:=[]
	; e.life:=[]
	; e.alpha:=[]
	e.color:=[]
	e.circleSize:=[size]  ; !!! since these never change, they only need to be set once
	; e.lineWidth:=[size] ; !!! since these never change, they only need to be set once
	e.coords:=[]
	e.alpha:=[255]
	; e.pattern:=[]
	; e.gravity:=[]
	; e.type:="sparks"
	
	Loop, % w//res
	{
		i:=A_Index
		x:=(i-1)*res
		Loop, % h//res
		{
			j:=A_Index
			y:=(j-1)*res
			argb := Gdip_GetPixel(pBitmap, x, y)
			rgb:=argb & 0x00FFFFFF
			e.color.Push(format("{:06x}", rgb))
			; e.alpha.Push(argb>>24)  ; !!! these are not needed for /every/ particle. Save some memory.
			; e.life.Push(1)          ; !!! these are not needed for /every/ particle. Save some memory.
			; e.speed.Push(0)         ; !!! these are not needed for /every/ particle. Save some memory.
			; e.circleSize.Push(size) ; !!! these are not needed for /every/ particle. Save some memory.
			; e.lineWidth.Push(size)  ; !!! these are not needed for /every/ particle. Save some memory.
			; e.pattern.Push("r")     ; !!! these are not needed for /every/ particle. Save some memory.
			; e.gravity.Push(0)       ; !!! these are not needed for /every/ particle. Save some memory.
			e.coords.Push({x:x*space,y:y*space})
		}
	}

	; !!! I put this stuff in here so I could change the size of stuff after we add them but before we draw them
	; psys.particles:=[]
	e:=psys.emitters[1]
	for k, tuple in e.coords
		psys.addParticle(tuple.x,tuple.y)

	Gdip_DisposeImage(pBitmap) ; !!! in this code it gets redrawn. get rid of the old
	Gdip_DisposeImage(hBitmap) ; !!! in this code it gets redrawn. get rid of the old
	return {psys:psys, w:w//res, h:h//res, guiId:guiId, hPic:hPic, res:res, space:space, size:size}
}

showParticleIm(pIm)
{
	if !WinExist("ahk_id " pIm.guiId)
		Gui, % pIm.guiId ":show"
	pIm.psys.clear()
	pIm.psys.draw(pIm.hPic)

	; !!! since you're not using .step(), particles never age. this isn't needed
	; pIm.psys.Particles[1].life:=1
	; 	for k, particle in pIm.psys.Particles[1]
	; particle.life:=1
	return
}
SpecialG wrote:Great stuff lol - If I have some time I'll fiddle around with it

It would be nice to make the initial script work on the full set of screens. (aka multi monitor support)
I tried a few things but to no avail for the time being..
you can using sysget to get the entire "virtual screen" (options 78, 79). but I advise against that. Do a smart way: get which monitor your mouse is on. use sysget to get the x/y/w/h of that monitor. if the monitor your mouse is on ISN'T the same as the last check, draw the canvas on the new monitor.
having 1 massive canvas will crank up the CPU usage and how much RAM is needed to store all the stuff.

I did this in one of my non-gui versions. I don't feel like adding it to the toy as it's just meant for experimenting. the real thing is the class, program the stuff yourself after you figured out the options you like. I might consider adding it later, but for now that's beyond the gui-toy's purpose.

This should help you get started:

Code: Select all

mouseGetPos, xxx, yyy
monCoords:=monitorAtCoords(xxx,yyy)


monitorAtCoords(xxx,yyy)
{
	sysGet, count, MonitorCount
	loop, %count%
	{
		sysGet, mCoords, monitor, %A_Index%
		if ((xxx>=mCoordsLeft && xxx<=mCoordsRight) && (yyy>=mCoordsTop && yyy<=mCoordsBottom))
			return {"mon":A_Index, "x1":mCoordsLeft, "y1":mCoordsTop
			, "x2":mCoordsRight, "y2":mCoordsBottom
			, "w": mCoordsRight-mCoordsLeft, "h": mCoordsBottom-mCoordsTop}
	}
}
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [GDI+][Class] Particle System 2.0

17 Jan 2017, 04:36

tidbit wrote: as for optimizing it, see the comments with "!!!"
Thanks for the input, appreciated. :thumbup:

I'm not exactly sure how you want the effects: to look.
For the flickering, consider,

Code: Select all

effects:
	;[...]
	;I:=particliseImage(sFile,20,3,7) ; Not sure you need to this every time.
	showParticleIm(I, false)
return

showParticleIm(pIm,clear:=1)
{
	if !WinExist("ahk_id " pIm.guiId)
		Gui, % pIm.guiId ":show"
	if clear
		pIm.psys.clear()
	pIm.psys.draw(pIm.hPic)
	return
}
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [GDI+][Class] Particle System 2.0

17 Jan 2017, 06:33

Hi tidbit,

this is really great stuff.

Two notes on particles_class.ahk after a first glance:
  1. setCanvas:

    Code: Select all

    if (drawOnThis="") ; fullscreen mouse mode
    {
    	if (ttt!="")
    		gui, %ttt%: destroy
    	ttt:=this.ID
    If needed, I think it should be swapped.
  2. draw:

    Code: Select all

    if (type="text")
    {
    	font:="Comic Sans MS"
    	, Gdip_FontFamilyCreate(font) <<<
    	, ttt:="x" vvv.x1 " y" vvv.y1 " c" alpha color " s" radius  " r0 " vvv.misc2
    	, ttt:=strSplit(Gdip_TextToGraphics(this.ggg, vvv.misc1, ttt, font,,,1), "|")
    	, ttt2:="x" vvv.x1-(ttt[3]//2) " y" vvv.y1-(ttt[4]//2) " c" alpha color " s" radius  " r0 " vvv.misc2
    	, Gdip_TextToGraphics(this.ggg, vvv.misc1, ttt2, font)
    	, Gdip_DeleteFontFamily(font) <<<
    	, this.drawCount+=1
    }
    <<< unnecessarily creates an GDI+ object which won't be freed.
User avatar
tidbit
Posts: 1272
Joined: 29 Sep 2013, 17:15
Location: USA

Re: [GDI+][Class] Particle System 2.0

17 Jan 2017, 11:20

Helgef wrote:
tidbit wrote: as for optimizing it, see the comments with "!!!"
Thanks for the input, appreciated. :thumbup:

I'm not exactly sure how you want the effects: to look.
something like this: https://www.openprocessing.org/sketch/105516
objects closer to the mouse get bigger, objects further go to their default size.
there's also this, but they get pushed not scaled. https://codepen.io/soulwire/pen/Ffvlo

Also for some more explanation:
the reason you don't need to add an alpha/circle size/other property for EVERY particle you add is because the emitters properties get applied to all particles (of that emitter). it's not 1 property for 1 particle, but instead it's 1 emitter for all particles, of that emitter.
just me wrote:Hi tidbit,
this is really great stuff.
Spoiler
Thanks!
1) I think it'd work either way. I did a bunch of testing this way and never got any errors, so I won't change what isn't broke.
2) whoops :D I assume it should be: font2:=Gdip_FontFamilyCreate(font) for that to work
rawr. fear me.
*poke*
Is it December 21, 2012 yet?
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [GDI+][Class] Particle System 2.0

17 Jan 2017, 12:18

2) It's included in Gdip_TextToGraphics().
SpecialG

Re: [GDI+][Class] Particle System 2.0

17 Jan 2017, 17:15

Thanks for the feedback and great idea about the canvas redraw on monitor switch :thumbup:
..i can apply that to more than one script i wrote lol

Also, over here a 2-screen canvas didn't even work for some reason :monkeysee:

and I get an error on Helgef's script.. first a Fail message for gdip-bitmap (download it and renamed to match) and then the gui-show with an empty/faulty gui-name..
No need to waste time on it since I can't myself for now but if you got any ideas on the top of your head i'm all ears ;)
tidbit wrote: you can using sysget to get the entire "virtual screen" (options 78, 79). but I advise against that. Do a smart way: get which monitor your mouse is on. use sysget to get the x/y/w/h of that monitor. if the monitor your mouse is on ISN'T the same as the last check, draw the canvas on the new monitor.
having 1 massive canvas will crank up the CPU usage and how much RAM is needed to store all the stuff.
My prediction for this new scripting year :

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: gwarble and 113 guests