So, I did a quick routine to create a classic 2D water ripple effect. The code, exe and test image are all included in the attachment.
(http://i904.photobucket.com/albums/ac242/wheeethefibble/webpics/watereffect.jpg)
On my 32GB iPod Touch (3rd generation - quite powerful) it really struggles, reducing framerate to a crawl and is thus not usable for anything that requires 60 FPS.
Is anyone aware of a way to do this kind of ripple effect without having to load and then draw a sprite as a line-by-line animation? Although covering the screen line by line could be very fast, if that was all that was involved, having to use the DRAWSPRITE command to do it is considerably CPU expensive. This kind of ripple effect was possible without too much trouble even on 16-bit computers but calling DRAWSPRITE 480 times to fill the screen even slows the FPS on my netbook.
I don't need any alpha-blending, collision detection or anything like that so is there any way to do what I've done without DRAWSPRITE?
LOADANIM "test.png", 1, 340, 1
GLOBAL waters[]
DIM waters[480]
GLOBAL f = 0
FOR n = 0 TO 3
FOR i = 0 TO 119
waters[i+(n*120)] = 5*SIN(f)
INC f
INC f
INC f
IF f >= 360 THEN f = f-360
NEXT
NEXT
f = 0
// MAIN LOOP
WHILE KEY(01) = FALSE
//MAIN LOOP
FOR i = 0 TO 479
DRAWANIM 1, i+5-waters[f], waters[f]-5, i // Draw every single line as a sprite
INC f
IF f = 480
f = f - 480
ENDIF
NEXT
DEC f
SHOWSCREEN
WEND
END
[attachment deleted by admin]
That's nice although I would not use it for a game cycle. Maybe for a menu or title screen!!!!
Hmmm... sounds like you could do with a "cheaper, faster" sprite routine, with much of the cleverness ripped out for speed. Or inline C/C++ to achieve the same results...
but how about this. You're doing a fair bit of math there, and I suspect that the CPU isn't that great at math. If you move the math out to a function and the sprite drawing to another function you could use the profiler to see if there is significant time being spent on the math. If there IS significant time being spent on the math, you MIGHT be able to improve on the time taken per frame by pre-calculating values and storing them in an array? Maybe a 2-dimensional array of floats would be quicker to access than recalculating each time?
Other little optimisations all help. For example, change:
INC f
INC f
INC f
to
INC f,3
I think I'll mention a cheaper, cruder and faster image copying routine at the requests forum. It could be helpful in circumstances like these.
Good suggestions Re: the math. In this case I already use an array to hold pre-calculated Sine multiples for how far the screen should distort. However, there are always a few things that can be done to optimise.
What I've been avoiding and should now think about facing is learning some C++! Many years ago I used to compliment my STOS Gaming Basic programs with 68000 assembly routines where I needed a speed boost on something simple. These are oddly similar circumstances. I'm reasonably experienced with Java and OOP so how hard could C++ be?
Nice. :)
Try using polyvector and newpolystrip.
You can load the image as a solid sprite and in your for-loop, change the texture position with the x position.
Surround the loop with the startpoly and endpoly, then put this in place of the sprite bit
newpolystrip
polyvector i+5-waters[f], waters[f]-5, i-1,0, rgb(255,255,255)
polyvector i+10-waters[f], waters[f]-5, i,0, rgb(50,50,155)
polyvector i+10-waters[f], waters[f]-5+480, i,480, rgb(50,50,155)
polyvector i+5-waters[f], waters[f]-5+480, i-1,480, rgb(255,255,255)
Also using the color you create a interesting fadeoff.
Okay I was wrong about the fadeoff and used one additional poly vector more than I should of, but here's the same code again with polyvector and a gradient routine simply applied.
// --------------------------------- //
// Project: watereffect2d
// Author: Scott A. Williams
// Based off code provided by 'Ragaril' from GLBasic forums
// Start: Wednesday, December 31, 1969
// IDE Version: 8.078
LOADSPRITE "test.png", 1
SETSCREEN 340, 480, 0
GLOBAL water[]
DIM water[480]
GLOBAL f = 0, c1 = 255, c2 = 0
FOR n = 0 TO 3
FOR i = 0 TO 119
water[i+(n*120)] = 5*SIN(f)
INC f, 3
IF f >= 360 THEN DEC f, 360
NEXT
NEXT
f = 0
WHILE KEY(1) = FALSE
STARTPOLY 1, 2
FOR i = 0 TO 479
c1 = 255 - (255 * (i/480))
c2 = 0 + (255 * (i/480))
IF i > 0 THEN POLYNEWSTRIP
POLYVECTOR water[f]-5-340, i+1, -340, i+5-water[f]+1, RGB(c1,c1,c2)
POLYVECTOR water[f]-5+340, i, 340, i+5-water[f], RGB(c1,c1,c2)
POLYVECTOR water[f]-5+340, i+1, 340, i+5-water[f]+1, RGB(c1,c1,c2)
INC f, 1
IF f = 480 THEN DEC f, 480
NEXT
ENDPOLY
DEC f, 1
SHOWSCREEN
WEND
END
[/cude]
Love it!
Scott_AW your changes work great! 8)
Not only is the wavy pattern now totally smooth in appearance but its significantly faster than calling drawsprite 480 times. Using a wavy background for my PowFish game is now netbook friendly! My iPod Touch is still dropping to half frame rate but heck, I was starting to overload onscreen detail anyway.
Thanks! =D
Thanks for the great example.
Thought I could update this thread with an improved routine. Using the code below still looks as nice but is far more optimised since it draws polys in steps of 16. Its even fast enough that I use a variation of it to display the backdrop for my PowFish game on the iPhone.
// --------------------------------- //
// Project: Water Effect
// Start: Wednesday, September 08, 2010
// IDE Version: 7.341
SETCURRENTDIR("Media") // seperate media and binaries?
SETSCREEN 320,480,0 // iPhone size 320x480 Window
LIMITFPS 60 // refresh at 60 frames per second
LOADANIM "test.png", 1, 340, 1 // should be 340x by 500y
GLOBAL waters[]
DIM waters[640]
GLOBAL f = 0
FOR n = 0 TO 4
FOR i = 0 TO 119
waters[i+(n*120)] = 5*SIN(f)
INC f
INC f
INC f
IF f >= 360 THEN f = f-360
NEXT
NEXT
f = 0
// MAIN LOOP
WHILE KEY(01) = FALSE
//MAIN LOOP
STARTPOLY 1,1
FOR i = 0 TO 479 STEP 16
POLYVECTOR 0, i, waters[f]+5, i+5-waters[f], RGB(255,255,255)
POLYVECTOR 0, i+16, waters[f+16]+5, i+21-waters[f+16], RGB(255,255,255)
POLYVECTOR 320, i+16, waters[f+16]+325, i+21-waters[f+16], RGB(255,255,255)
POLYVECTOR 0, i, waters[f]+5, i+5-waters[f], RGB(255,255,255)
POLYVECTOR 320, i, waters[f]+325, i+5-waters[f], RGB(255,255,255)
POLYVECTOR 320, i+16, waters[f+16]+325, i+21-waters[f+16], RGB(255,255,255)
INC f, 16
IF f >= 480 THEN DEC f, 480
NEXT
DEC f
ENDPOLY
SHOWSCREEN
WEND
END
I've modified it a bit. Added some shade and optimized a bit (using triangle strip)
Note that you really want to use an image with 340x500!
Quote// --------------------------------- //
// Project: Water Effect
// Start: Wednesday, September 08, 2010
// IDE Version: 7.341
SETCURRENTDIR("Media") // seperate media and binaries?
SETSCREEN 320,480,0 // iPhone size 320x480 Window
LIMITFPS 60 // refresh at 60 frames per second
LOADANIM "test3.png", 1, 340, 1 // should be 340x by 500y
GLOBAL waters1[]
DIM waters1[640]
GLOBAL waters2[]
DIM waters2[640]
GLOBAL f = 0
FOR n = 0 TO 4
FOR i = 0 TO 119
waters1[i+(n*120)] = 5*SIN(f)
waters2[i+(n*120)] = 5*COS(360-f)
INC f
INC f
INC f
IF f >= 360 THEN f = f-360
NEXT
NEXT
f = 0
// MAIN LOOP
WHILE KEY(01) = FALSE
//MAIN LOOP
STARTPOLY 1,2
LOCAL c=waters1[f]*20+(255-100)
LOCAL color1a=RGB(c,c,c)
c=waters1[f+16]*20+(255-100)
LOCAL color1b=RGB(c,c,c)
c=waters2[f/2]*20+(255-100)
LOCAL color2a=RGB(c,c,c)
c=waters2[f/2+16]*20+(255-100)
LOCAL color2b=RGB(c,c,c)
POLYVECTOR 320, 0, waters2[f]+325, 5-waters2[f], color2a
POLYVECTOR 0, 0, waters1[f]+5, 5-waters1[f], color1a
FOR i = 0 TO 479 STEP 16
c=waters1[f]*20+(255-100)
color1a=RGB(c,c,c)
c=waters1[f+16]*20+(255-100)
color1b=RGB(c,c,c)
c=waters2[f/2]*20+(255-100)
color2a=RGB(c,c,c)
c=waters2[f/2+16]*20+(255-100)
color2b=RGB(c,c,c)
POLYVECTOR 320, i+16, waters2[f+16]+325, i+21-waters2[f+16], color2b
POLYVECTOR 0, i+16, waters1[f+16]+5, i+21-waters1[f+16], color1b
INC f, 16
IF f >= 480 THEN DEC f, 480
NEXT
DEC f
ENDPOLY
SHOWSCREEN
WEND
END
Lovely effect Albert. :)
For some reason there were some jagged edges occurring. Look at the light beams going down into to water on the different versions for comparison. I wasn't sure why that was occuring but instead of working out why I just de-optimised the routine (sorry - I'm lazy) by modifying the older code with your new shading changes so that the POLY section looks like this: -
STARTPOLY 1,1
FOR i = 0 TO 479 STEP 16
LOCAL c=waters[f]*6+(255-30)
LOCAL color1a=RGB(c,c,c)
c=waters[f+16]*6+(255-30)
LOCAL color1b=RGB(c,c,c)
POLYVECTOR 0, i, waters[f]+5, i+5-waters[f], color1a
POLYVECTOR 0, i+16, waters[f+16]+5, i+21-waters[f+16], color1b
POLYVECTOR 320, i+16, waters[f+16]+325, i+21-waters[f+16], color1b
POLYVECTOR 0, i, waters[f]+5, i+5-waters[f], color1a
POLYVECTOR 320, i, waters[f]+325, i+5-waters[f], color1a
POLYVECTOR 320, i+16, waters[f+16]+325, i+21-waters[f+16], color1b
INC f, 16
IF f >= 480 THEN DEC f, 480
NEXT
DEC f
ENDPOLY