Underwater module
v1.0 for AGS 2.72+
Distorts a background in a wibbly wavy way.
Hard to show a screenshot, but you can see it in action in this demo:
http://www.kweepa.com/step/ags/tech/UnderwaterDemo.zip
Get the module here:
http://www.kweepa.com/step/ags/tech/Underwater11.zip
Video on youtube:
http://www.youtube.com/watch?v=EP1iFfDPXvY
Version history:
1.1 Added characters and objects (depending on baseline)
1.0 Initial version
Steve
Are you married? Wow, subspark will love this!!! Thanks a lot stevey!!
Is it possible to run this effect on only a small area?
Steve... that's awesome :o
I wish people would post videos of their modules in action. :P
Thanks, Steve! This will be very useful to a lot of developers here :)
Quote from: TerranRich on Wed 19/08/2009 15:42:56
I wish people would post videos of their modules in action. :P
Be my guest! It would take me longer to record, convert, and upload the video than to write the module! :=
Quote from: SSH on Wed 19/08/2009 11:04:19
Is it possible to run this effect on only a small area?
Yes, that would be possible. Are you thinking about a window in an underwater base or something like that? I'll have a think about the best way to handle the edges.
Quote from: Dualnames on Wed 19/08/2009 08:16:10
Are you married? Wow, subspark will love this!!! Thanks a lot stevey!!
Sorry, yes I am!
I considered posting this in sparky's thread...
Wow. Nice job. Anyway you can get that to work along with the character? It just doesn't seem right that the character doesn't have the same effect happen to him.
Quote from: Joseph DiPerla on Wed 19/08/2009 17:16:54
Anyway you can get that to work along with the character?
I'd have to have a third buffer, render the bg, characters and objects to that, then do the underwater effect on top (and hide the visible objects). I think it's easy enough to get the current frame for characters...
Quote from: SteveMcCrea on Wed 19/08/2009 17:50:42I think it's easy enough to get the current frame for characters...
Sure, that's easy enough:
ViewFrame *frame = Game.GetViewFrame(player.View, player.Loop, player.Frame);
DynamicSprite *sprite = DynamicSprite.CreateFromExisitingSprite(frame.Graphic);
if (frame.Flipped) sprite.Flip(eFlipLeftToRight);
Though you do have to use a DynamicSprite if the frame is flipped (otherwise you can just use the raw sprite number). You could avoid creating the sprite unnecessarily by doing something like:
ViewFrame *frame = Game.GetViewFrame(player.View, player.Loop, player.Frame);
DynamicSprite *sprite;
int graphic = frame.Graphic;
if (frame.Flipped) {
sprite = DynamicSprite.CreateFromExistingSprite(graphic);
sprite.Flip(eFlipLeftToRight);
graphic = sprite.Graphic;
}
I am assuming that you're using a DrawingSurface at some point which the character sprites would be drawn onto? Because at that point it's safe to delete the DynamicSprite (if any) of course.
Cool module. The functionality is very similar to the refraction part of my EffectObjects module, though that works on objects (as you can tell from the name) rather than backgrounds. Basically it turns any object into a lens which can scale/distort background, objects and characters behind it. I'm using 3.1.2, so DrawingSurface functions and CopyTransparencyMask are a great help. But I'm sure something similar could be done in 2.72.
The thing you have to remember if you want to RawDraw characters/objects onto the background before distorting it is to sort them by baseline first. Since characters and objects can move around and new characters can enter the room this has to be done every game loop, which is a bit of a pain but doesn't cause too much slowdown. Also, any walkbehinds within the distorted area would have to be faked by using objects.
Wow, if you can get this to work with the characters and objects too, that would be even better. I was actually going to ask about that in my first post but I had lost track of time and had to leave.
Thanks monkey & GG for the pointers.
New version uploaded with a new helper module FakeScreen that composites objects and characters (sorted, scaled and transparent) onto a background frame before the Underwater module does its work. A walkbehind hides the actual objects and characters.
The demo has also been updated to reflect the changes.
Steve
Quote from: SteveMcCrea on Thu 20/08/2009 06:05:17A walkbehind hides the actual objects and characters.
So you have to cover the entire room in a walkbehind area, or does the module apply the effect to said area?
And you're welcome...looked over your code. Snazzy stuff you've got going on in there. :D
Quote from: monkey_05_06 on Thu 20/08/2009 06:16:51
Quote from: SteveMcCrea on Thu 20/08/2009 06:05:17A walkbehind hides the actual objects and characters.
So you have to cover the entire room in a walkbehind area...?
Yup! This is the easiest way to keep all the properties of the objects and characters intact. If you want to draw a window or porthole in front, you just set the walkbehind baseline above the window baseline. Then you can have a character walk in front of the window or swim behind it.
Quote from: TerranRich on Wed 19/08/2009 15:42:56
I wish people would post videos of their modules in action. :P
Video on youtube:
http://www.youtube.com/watch?v=EP1iFfDPXvY
Hmm, what I actually really wanted was a reflective, wobbly surface of the water but only taking up a small part of the screen (e..g. in a fountain thats part of the background)
Then you want the Lake module!
http://www.adventuregamestudio.co.uk/yabb/index.php?topic=27356.0
You'd need to cover up a bit of it with an object.
Good work Steve! I knew someone would tackle my idea. Although I'm sure it was hardly a tackle.
Many cheers,
Sparky.
The demo looks great, I could watch it for ten minutes...
However I ran into problems using it in an 800x600 32bit game. It came out like this:
(http://img233.imageshack.us/img233/9853/underwaterweirdness.png)
(The background was a pencil line drawing from uncle-mum's Stediddy (http://www.adventuregamestudio.co.uk/yabb/index.php?topic=35868.msg469990#msg469990) game)
Before I added a full screen walkbehind the pink colour was constant and behind the characters. Now it flashes on and off - at about the default rate for background animation now that I think about it. I tried downgrading to 16 setting which had no effect and I lowered the game resolution but the magenta colour remained.
EDIT: Ignore all this, Steve. It looks like AGS corrupted the bitmap somehow when I exported it. Opening the file in MSPaint and saving it again made the magenta go away. Nothing to do with your module. Keep up the good work!
Quote from: Ali on Sat 22/08/2009 18:38:45Now it flashes on and off - at about the default rate for background animation now that I think about it.
Have you tried calling SetBackgroundFrame(0) in the player_enters_room event (unless the module already does this)?
Quote from: GarageGothic on Sat 22/08/2009 18:46:52
Have you tried calling SetBackgroundFrame(0) in the player_enters_room event (unless the module already does this)?
It does. :=
See the repeatedly_execute function below:
// Underwater module script
__Underwater Underwater;
export Underwater;
bool gEnabled = false;
float tt = 0.0;
float t = 0.0;
float a[5], b[5], c[5];
function __Underwater::Enable()
{
float scalar = 2000.0;
int i = 0;
while (i < 5)
{
a[i] = IntToFloat(Random(2000)*(2*Random(1)-1))/scalar;
b[i] = IntToFloat(Random(2000)*(2*Random(1)-1))/scalar;
c[i] = IntToFloat(Random(2000)*(2*Random(1)-1))/2000.0;
i++;
}
gEnabled = true;
}
function __Underwater::Disable()
{
gEnabled = false;
}
float get_gradient_x(int xi, int yi)
{
float x = IntToFloat(xi)/160.0 - 1.0;
float y = IntToFloat(yi)/160.0 - 1.0;
float dx = 0.0;
int i = 0;
while (i < 5)
{
dx += a[i]*t*Maths.Cos(a[i]*t*x + b[i]*t*y + c[i]);
i++;
}
return dx;
}
float get_gradient_y(int xi, int yi)
{
float x = IntToFloat(xi)/160.0 - 1.0;
float y = IntToFloat(yi)/160.0 - 1.0;
float dy = 0.0;
int i = 0;
while (i < 5)
{
dy += b[i]*t*Maths.Cos(a[i]*t*x + b[i]*t*y + c[i]);
i++;
}
return dy;
}
function offset_a_block(DrawingSurface *surf, int x, int y, int w)
{
int xoff = FloatToInt(1.0*get_gradient_x(x + w/2, y + w/2));
int yoff = FloatToInt(1.0*get_gradient_y(x + w/2, y + w/2));
DynamicSprite *ds = DynamicSprite.CreateFromBackground(1, x, y, w, w);
#ifver 3.00
surf.DrawImage(x - xoff, y - xoff, ds.Graphic);
#endif
#ifnver 3.00
RawDrawImage(x - xoff, y - yoff, ds.Graphic);
#endif
}
function repeatedly_execute()
{
if (gEnabled)
{
tt = tt + 0.01;
t = 2.0*Maths.Pi*Maths.Sin(tt);
SetBackgroundFrame(0);
// repeatedly grab a random chunk from bg 1 and paste it to bg 0, slightly offset
#ifver 3.00
DrawingSurface *surf = Room.GetDrawingSurfaceForBackground(0);
#endif
int i = 0;
while (i < 128)
{
i++;
int w = Room.Width/32;
int x = Random(Room.Width - 1 - w);
int y = Random(Room.Height - 1 - w);
offset_a_block(surf, x, y, w);
}
// draw some more around the player
ViewFrame *frame = Game.GetViewFrame(player.View, player.Loop, player.Frame);
int graphic = frame.Graphic;
int height = FloatToInt(IntToFloat(Game.SpriteHeight[graphic]*player.Scaling)/100.0);
int width = FloatToInt(IntToFloat( Game.SpriteWidth[graphic]*player.Scaling)/100.0);
int left = player.x - width/2;
int top = player.y - height - player.z;
i = 0;
while (i < 32)
{
i++;
int w = Room.Width/64;
int x = left - w/2 + Random(width - 1);
int y = top - w/2 + Random(height - 1);
if (x < 0) x = 0;
else if (x >= Room.Width - w) x = Room.Width - 1 - w;
if (y < 0) y = 0;
else if (y >= Room.Height - w) y = Room.Height - 1 - w;
offset_a_block(surf, x, y, w);
}
#ifver 3.00
surf.Release();
#endif
}
}
My God, Steve, you have a ton of modules, all of them very useful and amazingly well-done! I gotta see which ones I can use. ;D
I've got a way to go to catch up with SSH or monkey_05_06!
To be fair though Steve your modules tend to be way cooler than mine. Most of mine are based on other people's scripts (like AGSMuse and QueuedSpeech) or a generic concept that's not really that difficult (like GUIAnimation for example where I just change the GUI.BackgroundGraphic property).
Yours implement 3D effects and things which I frankly don't understand what's happening at all! ::)
For some reason everything stops moving during cutscenes. Any ideas?
EDIT: AH! I added "always" to "repeatedly_execute" and it did the trick.
Ah yes, that'll do it.
It's probably worth putting out a new version with that change.
Wow, this is really a great module. Is there by any chance a source of all those algorithms, you're using?
The source code is right up there ^^^. :=
The "magic" is in get_gradient_x/y, which just sum up some sine waves with different magnitude and phase, and are used to offset a block of pixels.
I don't have a specific reference. I just pulled the approach out of my arse. However, a quick web search for "2d fractal noise sum of sine waves" turned up this which seems similar:
http://developer.download.nvidia.com/SDK/9.5/Samples/samples.html#glsl_vertex_water
Hehe... that makes the module even more impressive :D
I once had a book about megademo-coding for Turbo Pascal, but unfortunately I've lost it :(
It was full of algorithms and 3d gimmicks... *sigh*
thank Steve , this module is simply amazing
Quote from: PuNKKoMmANDO77 on Thu 10/12/2009 11:35:57
thank Steve , this module is simply amazing
Glad you like it.
Let me know if you need any help integrating it into a game (that goes for everyone!). And also let me know if you release a game using it...
Hi. I want to implement something like that in a completely different game engine and I thought this module could help me out. ... But I've trouble understanding how it works. ^^'
Starting here :
a[i] = IntToFloat(Random(2000)*(2*Random(1)-1))/scalar;
Get a random number between 0 and 2000, multiply by... either 0 or 1 ? then divide by 2000. I think I'm reading something wrong.
Then in get_gradient
float x = IntToFloat(xi)/160.0 - 1.0;
What's that 160 doing here ? Why -1 ?
I'll just trust you on the way to calculate dx and dy.
offset_a_block
int xoff = FloatToInt(1.0*get_gradient_x(x + w/2, y + w/2));
We're using the center of the chunk of background to displace as the argument for get_gradient, right ?
repeatedly_execute
Are you displacing 128 random chunks of background ?
I understand that first loop (I think), the rest of the function lost me.
I hope I'm not too annoying. >.>
Quote from: Lufia on Tue 26/01/2010 15:30:04
a[i] = IntToFloat(Random(2000)*(2*Random(1)-1))/scalar;
Get a random number between 0 and 2000, multiply by... either 0 or 1 ? then divide by 2000. I think I'm reading something wrong.
Yup; multiply by either -1 or 1; yup.
It's just a random float between -1 and 1. More complicated than it needs to be, sorry!
Quote
float x = IntToFloat(xi)/160.0 - 1.0;
What's that 160 doing here ? Why -1 ?
The 160 is the screen width divided by two. The -1 then makes x between -1 and 1.
Quote
int xoff = FloatToInt(1.0*get_gradient_x(x + w/2, y + w/2));
We're using the center of the chunk of background to displace as the argument for get_gradient, right ?
Yup, that's right.
Quote
repeatedly_execute
Are you displacing 128 random chunks of background ?
I understand that first loop (I think), the rest of the function lost me.
Yes, that's right.
The rest of the function displaces some more blocks near the player.
Good luck!
First of all, I suck at scripting when it gets the tiniest bit complicated. So I was trying to use your module for a game (MAGS Underwater) and when using the fakescreen I don't really understand what are the parameters I need to put... one int for objects another one for characters and the baseline? I don't really get it (the numbers I 'intuitively' try result in error)
Hey, does someone has a backup of this code somewhere? I am really interested in the code :). Also the FakeScreen module, I couldn't find it's topic. :~(
grab (https://dam1976.home.xs4all.nl/AGS/modules/)
Thanks arj0n ! Just downloaded both modules! :]
thanks arjon + eri0o! i was also going to ask for underwater a couple days ago :)
I never knew I needed this module until now. :shocked:
Maybe I'm wrong to use this module. But I get an error in AGS 3.4.1. I only add underwater.Enabled(); in one of my rooms. Is it enough or I need other codes too?
Edit: Problem solved. I forgot duplicate frame. It works perfectly on 3.4.1 too.
Does anyone still have this module still? The link appears to be dead and it would be really handy for something I've been working on :(
Should be in this pack: http://www.maniac-mansion-mania.de/downloads/AGS/MODULES.rar
(GraphicModules/Graphical Effects)
I know this is an old module and probably not supported now but I have an issue. I'm using the Draw Behind so the it also puts the water effect on characters and objects. But having done that, I've found you can no longer click on items and objects (obviously).
Is there a way to set mouse clicks to pass through/ignore a walkbhind layer? I'm not sure there is but I thought I'd fire out the question.
I don't think you can do that easily.
I think the best option would be to modify the script to make FakeScreen write to a DynamicSprite and have the Underwater module modify that sprite and stick it on a non-clickable full screen GUI.
You can also draw on a graphic overlay
I'm using a game with 1366x768 (widescreen) backgrounds, and it's 32it colour.
When I use this module, the player and other on-screen objects show no change, and the background begins to sway wildly getting more and more distorted.
What am I doing wrong?
SOLVED: I was using the wrong resolution. Mine are 1366 wide, so lines 34/35/50/51 in module are all using 683.0 (half of 1366), not 160.0 (half of 320, the very small size).
eg:
Underwater.asc:
float get_gradient_y(int xi, int yi)
{
float x = IntToFloat(xi)/683.0 - 1.0;
float y = IntToFloat(yi)/683.0 - 1.0;
float dy = 0.0;
int i = 0;
while (i < 5)
{
dy += b[i]*t*Maths.Cos(a[i]*t*x + b[i]*t*y + c[i]);
i++;
}
return dy;
}
It's me again.
I'm using AGS 3.5.0.31 (p9)
Have Underwater working; Fakescreen not working.
I have an animated object which will not distort as the background is doing with Underwater.
No matter the combinations of src/dest backgrounds, or my baseline (=0 seems to work best), it will won't work - object remains undistorted.
I have background 0 (main), background 1 (copy of bg0, working space), and a spare bakcground 2 (used for something else, plain white image on it).
I also have a walkbehind on background 0, if this is significant.
Also: Underwater is above Fakscreen in the script list (though I doubt this matters).
Can anyone help? What am I doing wrong with Fakescreen that I'm not with Underwater?
I would have loved to use this module in my game as it's mostly set under water, From my tests with it it looked great...but as you have described, I ran into the same issues that the module doesn't support. There were a few ideas on how to fix this but they were beyond my coding abilities at the moment.
But if this gets resolved I'll be all over this module. I certainly keep an eye on this thread in the case that someone tweaks the module code to work with interactive/animated room objects.
eErio what are you waiting for? Use your coding magic to rewrite this module from the ground up in AGS 3.5 ;)
I don't remember if I did it or not, can you try the version here: https://ericoporto.github.io/agsModuleList/ ?
Wow this is so impressive!! 8-0
Is there a way to activate the effect only in one specific moment (cut scene) and then disable it?