Wednesday, September 13, 2006
Underwater effect
Basic idea: shift the pixel in horizontal and vertical direction sinusoidally.
Here it is assumed that buffer is the off-screen buffer (will be copied to the video buffer), width and height hold the dimension of the buffer. tick is the time variable, in this example it is taken using SDL_GetTicks function. Divide by 4 causes the oscillation period to be 4 seconds. Bonus for readers who figure out why it is masked with 1023 instead of modulo 1000.
In real-world, these calculations are expensive and thus should be helped with some look-up tables, at least for the sine function. Everything will look simpler.
unsigned char* ptr = buffer; int amp = width/64; const int tick = (SDL_GetTicks()/4) & 1023; for(int yi = 0; yi < height; yi++, ptr+= width) { int shift = amp/2 + amp/2*sin((4*yi/(double)height + tick/(double)1024)*2*M_PI); memmove(ptr+shift, ptr, width-shift); } for(int xi = 0; xi < width; xi++) { int shift = amp/2 + amp/2*sin((4*xi/(double)width + tick/(double)1024)*2*M_PI); ptr = buffer + xi + (height-1)*width; for(int c = 0; c < height-shift; c++, ptr -= width) *ptr = *(ptr-shift*width); }
Update: here is the screencast.
Comments:
<< Home
The & 1023 has the added bonus of looping the tick variable when it it is greater than or equal to 1024, as the mask sets it to 0.
A fancy optimisation that saves an if statement and thus a branch :)
Carmack taught me that too as it happens. I learnt it reading the Doom sources.
Fascinating that the underwater trick is so easy to do.
A fancy optimisation that saves an if statement and thus a branch :)
Carmack taught me that too as it happens. I learnt it reading the Doom sources.
Fascinating that the underwater trick is so easy to do.
I would think you would need more than just an if statement (unless the range of SDL_GetTicks() is quite restricted).
By using mod 1024 instead of 1000, you get to replace an integer division (which is how the mod is calculated) by a single logical and operation.
However, I would expect any compiler worth its salt should do that automatically for you if you had just specified %1024. Afterall, I couldn't help but notice that you expected that of the /4 (which is optimally a >>2) on the same line.
Post a Comment
By using mod 1024 instead of 1000, you get to replace an integer division (which is how the mod is calculated) by a single logical and operation.
However, I would expect any compiler worth its salt should do that automatically for you if you had just specified %1024. Afterall, I couldn't help but notice that you expected that of the /4 (which is optimally a >>2) on the same line.
<< Home