ID:2352979
 
Applies to:Dream Maker
Status: Open

Issue hasn't been assigned a status value.
I think that blur, motion blur, and drop shadow, would be far more useful if you could animate the x and y of them in some manner. Unfortunately, trying to do that right now will result in a "runtime error: Cannot animate abstract filter"
You can animate x and y of the filters. You can't animate them on a filter that isn't attached to an object.

What you're describing is either a bug in BYOND, or a problem in your code. Can you post the code you're trying to use to animate the x and y values of the filter?

This for instance won't work:

var/F = filter(type="motion_blur", x=0, y=0)
src.filters = F
animate(F, x=5, time=10)
animate(x=0, time=10)
sleep(21) src.filters = null

In this case F is an abstract filter; you can't animate it. You have to animate src.filters[1] (assuming it's the only filter) instead.

var/F = filter(type="motion_blur", x=0, y=0)
src.filters = F
animate(src.filters[1], x=5, time=10)
animate(x=0, time=10)
sleep(21) src.filters = null
That's really dodgy, and seems to mean that having more than one filter at any one time will cause problems.
It also seems to be you can't animate both x and y at the same time without having a new animate proc.
I can animate motion blur, but I cannot animate blur using the same code.
If you need to manage multiple filters, obviously the code has to be more nuanced. You might even need something to keep track of which filters are applied to an object so you can animate properly.

There are two reasons you can't animate the result of a filter() call. First, that's because that object is just a placeholder for setting values; it doesn't belong to any particular object or appearance. Appearance filters are referenced by index and a reference to the object themselves. The second reason is because Appearances are immutable; you can't change a component of an Appearance and have it affect all objects using that component.

Internally, here's how filters work.

All filters share the FILTER_REF type. The internal FilterRef object contains a src (refcounted), and an index. There are four types of FilterRef.

The first type, created by filter(), sets the FilterRef's src to an internal object, a special ref that points to a mutable filter. The mutable filter doesn't "belong" to any object; if you assign it to an object, you're only assigning a copy.

The second type of FilterRef is an immutable filter. These act a lot like strings and Appearances: Each unique immutable filter has an ID of its own. The reasons for doing it this way are more technical than I'd like to get into here, but it basically ties in with the fact that Appearances themselves are also immutable.

The third type has an Appearance-bearing object (i.e., an atom or an image) as src, and has index=0. This indicates it refers to the entire filter list for that object. This is what lets you use the index operator, len, etc.

The last type of FilterRef is the same as the third but it has index set to a positive value, indicating it points to the Nth filter for an object. This is the only ref that you can animate, because then animate() knows it's changing the Appearance for a particular object, and it knows which specific filter (by number) it's operating on. If you change vars on this object, you're actually changing the Appearance of the object through a whole cascade of actions.

Now going back to your issue, I understand the problem is that you might use multiple filters, adding and removing them according to various routines, and you want to be sure that after a sleep() you're working with the right filter. For that you'll want to keep track internally of which filters are applied, like so:

datum   // since atoms and images have to inherit this code
var/list/filtersbyref

proc/AddFilter(F)
if(!filtersbyref) filtersbyref= new
filtersbyref += F
filters += F
return filters[filters.len]

// return a direct reference to the FilterRef that can be used for animation or changing values
proc/GetFilter(F)
if(!filtersbyref) return null
var/idx = filtersbyref.Find(F)
if(idx) return filters[idx]

proc/RemoveFilter(F)
if(!filtersbyref) return null
. = filtersbyref.Find(F)
if(.)
filtersbyref.Cut(., .+1)
filters.Cut(., .+1)
if(!filtersbyref.len) filtersbyref = null

You would use those routines for adding and removing all filters. Thus your animation code would look like this:

var/F = filter(type="motion_blur", x=0, y=0)
animate(AddFilter(F), x=5, time=10)
animate(x=0, time=10)
sleep(21) RemoveFilter(F)

You need to call GetFilter() every time you need to access the filter object--for more value changes or an animation--and there may have been a sleep() or spawn().

The downside to the method above is that you're holding onto the mutable filter for way longer than you need to, since it's just something you're using as a "handle". There are ways you could alter this to get around that problem, but for handling special effects like short-term animations this should do everything you want it to.
Thank you for your very detailed explanation, that's extremely helpful! That said, I'm still experiencing troubles animating (non motion) blurs, and it will not allow me to animate both x and y at the same time.
Can you show me the code you're using? It ought to handle both just fine.
world
icon_size = 32
view = 6
fps = 60

/mob
step_size = 8
icon = 'mob.png'

/mob/verb/testmotionblur()
filters = null
filters += filter(type = "motion_blur")
animate(filters[1],x = 5,time = 30,easing = BOUNCE_EASING) // this bounces around into a motion blur.

/mob/verb/testblur()
filters = null
filters += filter(type = "blur")
animate(filters[1],x = 5,time = 30,easing = BOUNCE_EASING) // this immediately becomes a blur.

/mob/verb/clearfilters()
filters = null

/turf
icon = 'turf.png'
I don't see in that code where/how you're trying to animate x and y at the same time. That's what I'm mainly curious about.
Oh, I got the x and y animation to work. Probably just being stupid on my end; sorry. The motion blur vs blur thing still exists though
In response to DrCelt
DrCelt wrote:
Oh, I got the x and y animation to work. Probably just being stupid on my end; sorry. The motion blur vs blur thing still exists though

The blur filter has a size parameter, not x and y.