0

I have two images:
bg Image1 And overlay Image2 (which height is bigger than bg image1)

Now I need to place [Image2] over [Image1] with blend mode multiply. But after that I need to animate Image2's Y position but keep blend mode so to get an animation like this: https://www.youtube.com/watch?v=D4Gqm9_Eo68

So how can I achieve that?
May be I should use OpenGL? If yes, then how exactly?

Spektre
  • 49,595
  • 11
  • 110
  • 380
arturdev
  • 10,884
  • 2
  • 39
  • 67
  • the video is blank ... what effect you want to achieve ? colored scanline highlight going up/down inside image1 or the background (out of range of image2) will be black ? anyway yes you can do this in OpenGL relatively easily ... but if you got pixel access that this is done with simple 2 nested for loops rendering although on ios devices that could be slow depending on the HW architecture... – Spektre Nov 26 '15 at 12:19
  • @Spektre I've updated the video url. Please check that. – arturdev Nov 26 '15 at 12:22
  • how did u make video? you have already made what you wanted... :D :P – Fahim Parkar Nov 26 '15 at 12:28
  • @FahimParkar The video was made by designer :D – arturdev Nov 26 '15 at 12:31
  • oldstyle OpenGL or GLSL? render quad with 2 textures combined by blending. one texture is fixed (left image) and covers whole quad and the second is blended with repeat coordinates set. x axis covers whole quad and y-axis covers just a part of right texture covering full renderd quad. The animation is done simply by changing the offset of the second texture y-TexCoord ... So you need MultiTexture and Blending ... no need for alpha channel as this is color masked – Spektre Nov 26 '15 at 15:03
  • @Spektre yes, but I don't know OpelGL at all. Can you bring an example of code? – arturdev Nov 26 '15 at 20:59

2 Answers2

2

I do not code for IOS and have no clue of platform you are coding for (memory,speed,gfx capabilities). From your Question I got the impression you have no clue of rendering and also the animating part...

  1. the easiest way would be encode it yourself

    If you got pixel access then it is just a matter of 2 nested for loops copying/combining pixels of texture to target color. I usually use GDI and Bitmap->ScanLine[] for this but as mentioned I have no clue if you have something similar on IOS.

  2. 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:

    effect

    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 ...

This is simple VCL single form app with single timer in it (interval=20ms).

  • init() just allocates space for textures in gfx card and load the images to it.
  • ogl_draw() renders the effect of yours ...
  • Timer1Timer(TObject *Sender) is called on each timer event and just force to render frame and update animation ... it goes up through the gradient and then down ...

    This is the result:

    result

    Of coarse it is animated but I am to lazy to catch a video of this...

[edit1]

Here link to download the whole BDS2006 project download

Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Thank you very much! Can you send me your project's archive please? (mkrtarturdev@gmail.com) – arturdev Nov 27 '15 at 12:01
  • @added edit1 with link ... also delete the comments so you do not get bots exploiting your email address – Spektre Nov 27 '15 at 12:18
  • One more question. Can you tell me, what part of your code exactly do the blending job? :) – arturdev Dec 03 '15 at 19:57
  • @arturdev that between `glBegin` and `glEnd` "draws" `QUAD` (4 vertex polygon) so I pass the coordinates of polygon vertexes and to whivh point in which texture it coresponds (is mapped to). the rest just configures the OpenGL to render filled polygons with 2 textures blended together ... you do not mix the colros directly in opengl the combiners do that for you ... (but still can be done with GLSL but that is too much to start with for a rookie) – Spektre Dec 03 '15 at 20:30
0

What you need is:

- drawInRect:blendMode:alpha:
  • 2
    Expand on the answer with details on explanation so that the OP knows what you are saying and in what context. – TheLethalCoder Nov 26 '15 at 15:22
  • But how to animate that? How can I change Y position of gradient overlay image, and force to redraw while animating? – arturdev Nov 26 '15 at 20:59