Ah! Vale!
Pues yo lo que hago es coger la imagen original, la doy la vuelta, y la aplico un algoritmo que le provoca las perturbaciones al agua:
Es bastante sencillo, pero como lleva funciones trigonométricas, lo que hago es primero precalcular los valores, guardarlos en un array, y luego ya utilizar dichos valores.
A la hora de pintar la pantalla hago lo siguiente:
Pinto el frame generado.
Calculo el reflejo.
Lo pinto.
Para ello tengo tres imágenes: una con el frame generado, otra con el mismo frame cabeza abajo, y otra sobre la que pinto el efecto.
Lo primero es decidir el número de frames que vas a tener para generar el agua. A más frames, más calmada parece.
Vamos al meollo:
Tenemos dos arrays:
Private m_afRadians(NUM_FRAMES - 1) As Double
Private m_aiDespY(NUM_FRAMES - 1)() As Integer
m_afRadians va a ser un array que va a tener guardados los valores de 0 a 2*PI en intervalos de 2*PI/NUM_FRAMES. El hecho de ir de 0 a 2*PI viene del hecho de que las funciones trigonométricas son en radianes.
m_aiDespY es un array de dos dimensiones. La primera dimensión es el número de frames, y en la segunda guardamos para cada frame los valores de una función que tiene esta pinta (ASCII-ART!!!)
Código:
_
_ / \
_ / \ / \
/ \ / \ / \ /
\_/ \ / \ / ...
\_/ \ /
\_/
Es decir, es un seno, pero modificándolo para que según se aleja de X=0 tenga una amplitud mayor (tiene una pinta de una ola, más o menos)
El tamaño de la segunda dimensión tiene que ser la altura de la imagen que va a hacer de reflejo del agua.
Para rellenar el array, se puede hacer con el siguiente bucle:
Código:
For i = 0 To NUM_FRAMES - 1
m_afRadians(i) = CDbl(2 * Math.PI * i) / CDbl(NUM_FRAMES)
Next
For i = 0 To NUM_FRAMES - 1
Array.Resize(m_aiDispY(i), m_imgFlip.Height)
For j = 0 To m_imgFlip.Height - 1
m_aiDispY(i)(j) = CInt((m_imgFlip.Height / DISTORTION) * (CDbl(j) + 2 * DISTORTION) * Math.Sin(CDbl((m_imgFlip.Height / DISTORTION) * (m_imgFlip.Height - j)) / CDbl(j + 1) + m_afRadians(i)) / CDbl(m_imgFlip.Height))
Next
Next
La línea:
Código:
m_aiDispY(i)(j) = CInt((m_imgFlip.Height / DISTORTION) * (CDbl(j) + 2 * DISTORTION) * Math.Sin(CDbl((m_imgFlip.Height / DISTORTION) * (m_imgFlip.Height - j)) / CDbl(j + 1) + m_afRadians(i)) / CDbl(m_imgFlip.Height))
lo que hace es generar los valores del seno ese que he pintado antes.
m_imgFlip es la imagen que vamos a usar para el reflejo.
DISTORTION es una constante, que cuanto mayor es, más pronunciado es el efecto (no pasarse con el valor, ojo)
Entonces, después de haber precalculado esa función, qué es lo que hacemos?
Para cada frame, cogemos la imagen que hemos generado (la imagen hecha a partir de tiles, es decir, el frame actual sin efecto). Esa imagen ocupa aproximadamente la mitad de la pantalla.
Guardamos una copia de la imagen dada la vuelta (es decir, cabeza abajo)
Incrementamos en uno una variable que indica el frame actual (que va de 0 a NUM_FRAMES y vuelta a 0)
Y ahora generamos el efecto del agua (lo pongo en pseudocódigo):
Código:
For iLine = 0 To m_imgFlip.Height - 1
' Obtenemos el valor del seno precalculado para el frame actual.
iDespY = m_aiDispY(iFrame)(iLine)
' Si el valor de la línea actual es menor que -iDespY o la
' suma de iDespY + la línea actual es mayor que el tamaño
' de la imagen dada la vuelta:
If (iLine < -iDespY) OrElse (iLine + iDespY) >= m_imgFlip.Height Then
'Copiar la linea iLine de la imagen dada la vuelta a la línea
'iLine de la imagen con el efecto.
Else
'Copiar la línea iLine + iDespY de la imagen dada la vuelta
'a la línea iLine de la imagen con el efecto.
End If
Next
Para copiar la línea iLine, pues se hace un Blt (o como se haga en el lenguaje de tu elección) de la línea dada la vuelta a la línea actual.
Y ya está... Por cierto, qué mal me explico...

[/code]