OpenGL
as you have no OpenGL experience then I do not advice to use GLSL as it could be too much from start. Things like setting up OpenGL environment and explaining how OpenGL program works would be too long even for me (and I am used to lengthy answers). So I would skip that (you need to google some tutorial for it) anyway see:
As this require MultiTexturing you will also need that extension (At least I think those are not in OpenGL 1.0 natively). I advice to use lib for it like GLEW or whatever else.
The idea is to render quad (rectangle) with 2 textures at once something like this:

The Quad Vertex coordinates are fixed (dependend on screen and image resolution/aspect ratio). Texture0 is also fixed And Texture1 has fixed one axis and the second is changing... where:
t
is the animation parameter t=<0,1>
T
is used gradient chunk size T<1.0
The animation is done by changing t
by some small step each frame for example increment and wrap around or use sinus...
You need to remember that standard OpenGL knows only power of 2 textures so you need to resize/crop/resample your textures to match this criteria. I do this like this:

Also you need to handle aspect ratio difference between your App OpenGL screen and image ... I used a short cut so the OpenGL view is square and the image is resized to square too.
Now when using MultiTexturing you need to properly set up the Texture combiners to match your needs. It has been ages I used that so I do not remember it at all and too lazy to study that again as I use GLSL now ...
Luckily it looks like that default OpenGL settings of this do just what you want. So here some C++/VCL based code (without the OpenGL environment setup which is platform dependent):
//---------------------------------------------------------------------------
const int _txrs=2; // max number of textures
GLuint txrid[_txrs],txrids=0; // texture ids
GLfloat t=0.0,T=0.1,dt=0.1; // animation texture coordinates
void init()
{
glGenTextures(_txrs,txrid);
// textures
Byte q;
unsigned int *pp;
int xs,ys,x,y,adr,*txr;
union { unsigned int c32; Byte db[4]; } c;
Graphics::TBitmap *bmp=new Graphics::TBitmap; // new bmp
// image texture
bmp->LoadFromFile("effect_image.bmp"); // load from file
bmp->HandleType=bmDIB; // allow direct access to pixels
bmp->PixelFormat=pf32bit; // set pixel to 32bit so int is the same size as pixel
xs=bmp->Width; // resolution should be power of 2
ys=bmp->Height;
txr=new int[xs*ys]; // create linear framebuffer
for(adr=0,y=0;y<ys;y++)
{
pp=(unsigned int*)bmp->ScanLine[y];
for(x=0;x<xs;x++,adr++)
{
// rgb2bgr and copy bmp -> txr[]
c.c32=pp[x];
q =c.db[2];
c.db[2]=c.db[0];
c.db[0]=q;
txr[adr]=c.c32;
}
}
glEnable(GL_TEXTURE_2D); // copy it to gfx card
glBindTexture(GL_TEXTURE_2D,txrid[txrids]); txrids++;
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xs, ys, 0, GL_RGBA, GL_UNSIGNED_BYTE, txr);
glDisable(GL_TEXTURE_2D);
delete[] txr;
// gradient texture
bmp->LoadFromFile("effect_mask.bmp"); // load from file
bmp->HandleType=bmDIB; // allow direct access to pixels
bmp->PixelFormat=pf32bit; // set pixel to 32bit so int is the same size as pixel
xs=bmp->Width; // resolution should be power of 2
ys=bmp->Height;
txr=new int[xs*ys]; // create linear framebuffer
for(adr=0,y=0;y<ys;y++)
{
pp=(unsigned int*)bmp->ScanLine[y];
for(x=0;x<xs;x++,adr++)
{
// rgb2bgr and copy bmp -> txr[]
c.c32=pp[x];
q =c.db[2];
c.db[2]=c.db[0];
c.db[0]=q;
txr[adr]=c.c32;
}
}
glEnable(GL_TEXTURE_2D); // copy it to gfx card
glBindTexture(GL_TEXTURE_2D,txrid[txrids]); txrids++;
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xs, ys, 0, GL_RGBA, GL_UNSIGNED_BYTE, txr);
glDisable(GL_TEXTURE_2D);
delete[] txr;
T=0.4; // 40% of gradient height cover the whole image
dt=0.015*T; // animation step 1.5% of image
delete bmp;
}
//---------------------------------------------------------------------------
void TForm1::ogl_draw()
{
// clear buffers
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
// unit matrices ... no projections ... so view is just <-1,+1>
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glDisable(GL_DEPTH_TEST); // no Z-buffer for 2D
glDisable(GL_CULL_FACE); // no strict polygon winding
glDisable(GL_TEXTURE_2D);
// bind textures
glActiveTexture(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,txrid[1]);
glActiveTexture(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,txrid[0]);
glColor3f(1.0,0.0,1.0);
// render QUAD
glColor3f(1.0,1.0,1.0);
GLfloat t0=t,t1=t+T;
glBegin(GL_QUADS);
glMultiTexCoord2f(GL_TEXTURE0,0.0,0.0);
glMultiTexCoord2f(GL_TEXTURE1,0.0,t0);
glVertex3f(-1.0,+1.0,0.0);
glMultiTexCoord2f(GL_TEXTURE0,0.0,1.0);
glMultiTexCoord2f(GL_TEXTURE1,0.0,t1);
glVertex2f(-1.0,-1.0);
glMultiTexCoord2f(GL_TEXTURE0,1.0,1.0);
glMultiTexCoord2f(GL_TEXTURE1,1.0,t1);
glVertex2f(+1.0,-1.0);
glMultiTexCoord2f(GL_TEXTURE0,1.0,0.0);
glMultiTexCoord2f(GL_TEXTURE1,1.0,t0);
glVertex2f(+1.0,+1.0);
glEnd();
// unbind textures so it does not mess any rendering after this (texture unit 0 at the end !!!)
glActiveTexture(GL_TEXTURE1); glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,0);
glActiveTexture(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D,0);
// force to render qued OpenGL rendering and swap double buffers
glFlush();
SwapBuffers(hdc); // this is platform dependend !!!
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
ogl_draw();
t+=dt; // step the animation
if ((dt>0.0)&&(t+T>1.0)) { t=1.0-T; dt=-dt; } // handle if hit top
if ((dt<0.0)&&(t <0.0)) { t=0.0; dt=-dt; } // handle if hit bottom
}
//---------------------------------------------------------------------------
As you can see it is quite a bit of code. If you use some lib to load textures and handle stuff most of it will go away (I use mine engine for this so it took mi while to get the pieces together again so it is usable standalone without lib). Do not forget to init GLEW or whatever to get access to MultiTexturing ...