Images with 'wavy sine effect'

BlitzMax Forums/BlitzMax Programming/Images with 'wavy sine effect'

Hello all,

I was wondering if it is possible (and ofcourse, how) to create a 'wavy sine effect' over certain images every few frames to make it wave.

I recorded a video directly from my emulator (it's from Super Metroid for the SNES) while playing with some background layers for reference to show you what I mean:

Video (4,51 MB)

It's not the waving up and down ~32 pixels, but rather seperate horizontal lines waving left and right ~1-2 pixels (you might have to zoom the video). As you can see both the background and the water overlay have that wavy effect, although the water overlay might be a bit hard to see.

Sprites used in-game:

Background:


Water overlay:


If anyone could take a look at it and tell me if this is managable with standard BlitzMax functionality (or with some graphics module), I'd be happy.

You can do it, but it's a struggle for Max to distort an entire screen's worth of image data (Blitz, B+ and B3D have a much easier time with this sort of thing) so you're going to have to manipulate the tiles instead. This should get you going:

SuperStrict
SeedRnd( MilliSecs() )

Const GWIDTH:Int = 800
Const GHEIGHT:Int = 600

Graphics GWIDTH,GHEIGHT,0

For Local circleIndex:Int = 1 To 1000
	SetColor Rand(100,200),Rand(100,200),Rand(200,255)
	Local size:Int = Rand(10,20)
	DrawOval Rand(0,127), Rand(0, 127),size,size
Next
SetColor 255,255,255

Local tile:TPixmap = GrabPixmap(10,10,64,64)
Local SineBase:Int = 0
Local TILED_MODE:Byte = True

While Not KeyHit(KEY_ESCAPE)
	If KeyHit(KEY_SPACE) Then TILED_MODE = 1-TILED_MODE

	If TILED_MODE
		DrawPixmap tile,0,0
		For Local scanline:Int = 0 To 63
			Local subPixmap:TPixmap = GrabPixmap(0,scanline,63,1)
			tile.Paste(SubPixmap,Cos((SineBase+scanline)*6.0)*2.0,scanline)
		Next	
		SineBase:+1
		
		For Local X:Int = 0 To 12
		For Local y:Int = 0 To 9
			DrawPixmap tile,x*64,y*64
		Next
		Next
		DrawText "Currently distorting tile. Press space to toggle.",10,10
	Else
		For Local X:Int = 0 To 12
		For Local y:Int = 0 To 9
			DrawPixmap tile,x*64,y*64
		Next
		Next	
		
		For Local scanline:Int = 0 To GHEIGHT - 1
			Local subPixmap:TPixmap = GrabPixmap(0,scanline,GWIDTH-1,1)
			DrawPixmap subPixmap,Cos((SineBase+scanline)*6.0)*2.0,scanline
		Next
		SineBase:+1
		DrawText "Currently distorting entire screen. Press space to toggle.",10,10
	EndIf
		
	Flip
	Cls
Wend


Ah, thanks. Exactly what I was looking for. The whole screen distort runs kinda slow (0.5 FPS) while the tile distort runs smooth.

Could you also post a B3D minimal test case for the whole screen so I can look at that, too? I'm not sure how it handles pixmaps there.

The whole screen distort runs kinda slow
Yeah, exactly what you need to be aware of. The B3D equivalent (of fullscreen distort) would be...
Graphics 800,600,0,2
SetBuffer BackBuffer()

Const KEY_ESCAPE = 1

For circleIndex = 1 To 1000
	Color Rand(100,200),Rand(100,200),Rand(200,255)
	size = Rand(10,20)
	Oval Rand(0,127), Rand(0, 127),size,size
Next 
tile = CreateImage(64,64)
GrabImage tile,10,10

SineBase = 0

While Not KeyHit(KEY_ESCAPE)
	TileImage tile,0,0

	For currentScanline = 0 To 599
		CopyRect 0,currentScanline,800,1,   Cos((SineBase+currentScanline)*6.0)*2.0,currentScanline,  BackBuffer(),BackBuffer()
	Next
	SineBase = SineBase+1
	
	Flip
	Cls
Wend


In order to "wave" one larger image:

Would it be faster to "precalc" each of the images needed and save them in VRAM. - So one would need no math in the drawing routine at all?

I'm thinking of manipulating stuff like game logos etc.

Or use the 3D card directly by programming a mesh. Then you can do circular ripples and the like...

@ Grey Alien: Do you have some example code? I have no experience with GL whatsover and I'm not even sure how to work with meshes.

@ Grey Alien: Do you have some example code?
Regrettably no, otherwise I'd be doing it too! But I do know that meshes are the way to get loads of decent effects.

MiniB3D might be a worthwhile place to start -- should simplify mesh construction etc

@GA, Have you got links to any tutorials/papers/examples/whatever?

perhaps. A while back I was talking about making a scrolling tile game using a mesh and I think someone sent me some sample code (or posted it in that thread) but I never got round to using it. The idea with a mesh is you can warp the vertexes as you see fit so you could make ripple effects or sine waves etc. But I real know very little about it as my 3D library knowledge is minimal (I only know old school 3D programming, nothing modern).

NEHE tutorial 11 covers a sin wave flag effect in OpenGL, in theory you should be able to get this to work in BlitzMax under the OpenGL drivers.

But there is probably a nice pixel/vertex shader version somewhere that might work better with the the modern GPU's, only your moving out of BlitzMax's current feature set then.

Although a simple pregenerated animation using pixmaps->images would probably work better... all you would have to do is copy the image pixel by pixel with a waved based x (or y) offset for each line and repeat offsetting the effect until a full animation cycle is created, in theory!

There are old Blitzmax versions of many of the NeHe tutorials available, including #11 here:
http://perso.club-internet.fr/gilles.keil/Bmax/Nehe_Tutorial.zip

Unfortunately it would still need some rewriting, since BlitzMax has changed around a bit since that source was written and it won't compile as-is anymore.

Might be terrible idea but could you use one of the drawimagerect (or setuv) code archives with setorigin to draw a strip of each image offset by 1-2 pixels?

taking the drawimagerect approach a bit furthur.. i have written the below so it loads in an animimage.

sine height must be a factor of the image height.
i have used the first image as sine.png (64*128)
sine_height = 2
sine_speed = 8
sine_depth = 5
Graphics 800,600

sine_img:timage = LoadAnimImage("sine.png",64,sine_height,0,128/sine_height)

' sine angle
angle:Int = 0

While Not KeyDown(key_escape)

	' new sine
	angle=(angle+sine_speed) Mod 360	
	
	' draw background with sine	
	y:Int = 0
	While y < GraphicsHeight()
	
		offset = Sin(angle+y)*sine_depth

		x:Int = offset
		While x < GraphicsWidth()
		
			DrawImage sine_img,x,y,(y/sine_height) Mod (128/sine_height)
			x:+64
		Wend

		y:+sine_height
	Wend
	Flip
Wend 


Is there a way to create the animimage on the fly out of the original one?