Manipulating 2D Images

Alright, What I'm looking to learn how to do is make effect like the "Geiss" screensaver.  In other words, I need to know how to take a 2D image, and then warp it.  The 2 main effects that I want to know how to do are...
1) Where the screen zooms towards you (I think it's called Blitter feedback)
2) Where a spiral moves over the image. (I like the entire range of these effects)

The closest I've come to understanding these effects is that they use tables, and then I'm assuming they modify the tables using an equation, then render the table.  Also, the table equations seem to be polar ones..

I found one equation set that seems to do d=d*d;and r=r*r
(where d=distance and r=angle) to the table, and it produces a "hill" effect.

Any help would be greatly apprecatied!
FirefunkAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

nils pipenbrinckCommented:
the geiss effect is pretty simple.. it's a feedback effect which generates a new image from the last rendered one.

to render the new image you need a table. The table has one entry for each pixel of the image. in this entry you can look up from where to copy the pixel of the previous frame.


some pseudo code to render a frame: (for a 320*240 resolution)

int table_x [320*240];
int table_y [320*240];

int i=0;
for (int y=0; y<240; y++)
for (int x=0; x<320; x++)
{
  newimage[i] =  oldimage[table_y[i] * 320 + table_x[i]);
  i++;
}

show (newimage);
memcpy (oldimage, newimage, ...)


the trick of the geiss screensaver is, that it doesn't only read out one pixel, but 4 and do a bilinear interpolation between them. That's where the cool smoothing comes from.

to do so you have to store the coordinates in your arrays with more precision than simple integer. I use fixedpoint arithmetics and render the stuff with a hand full of mmx instructions.

(If you need help ask me.. I can give you working code if you want..)



now you need to calculate the tables.

this little code generates a zooming effect..


i=0;
for (int y=0; y<240; y++)
for (int x=0; x<320; x++)
{
  table_x[i] = (x-160)*1.1;
  table_y[i] = (y-120)*1.1;
  i++;
}

and this is something like your twirl effect:

i=0;
for (int y=0; y<240; y++)
for (int x=0; x<320; x++)
{
  float xx = x-160;
  float yy = y-120;

  // distance from center of screen;
  float dist = sqrt(xx*xx+yy*yy)*0.01;

  // rotate based on distance and
  // zoom a little bit:

  float s = sin(dist)*1.1;
  float c = cos(dist)*1.1;
  table_x[i] = 160+c*xx-s*yy;
  table_y[i] = 120+c*yy+s*xx;
  i++;
}

I hope you got the idea..

again, if you have any further questions ask me..

  Nils




0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
FirefunkAuthor Commented:
Thank you SO much!  We need more people like you in this world!

I'd love to see some working code if you wouldn't mind! If you want to get in contact with me, please just use my E-mail : Firefunk@bigfoot.com
(If you want to)

Thank you so much again....You've just helped me more today than I've been able to find for the last month!

Thank you!!

0
nils pipenbrinckCommented:
hehe

that's funny.. I've worked the whole day on some eyecandies here...


and since I was in the mood to code here is the example code I talked about (it's ugly dos-code... but you should get it up and running)...



#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <math.h>


int  table_x[320*200];
int  table_y[320*200];
char buf1[320*200];
char buf2[320*200];

int lerp (const int a, const int b, const int x)
{
  // linear interpolation
  return a + (((b-a)*x)>>16);
}

void render (char * dest, char * source)
{
  int i;
  int * tabx;
  int * taby;
  tabx = table_x;
  taby = table_y;
  for ( i=0; i<320*200; i++)
      {
    int x,y,offset,c,d;
    x=*tabx++;
    y=*taby++;
    offset = (x>>16)+320*(y>>16);
    c = lerp(source[offset],     source[offset+1],       x&0xffff);
    d = lerp(source[offset+320], source[offset+1+320], x&0xffff);
    *dest++ = lerp (c,d, y&0xffff);
  }
}

void make_table (void)
{
  // zoom effect..
  int x,y,i;
  i=0;
  for (y=0; y<200; y++)
  for (x=0; x<320; x++)
  {
    table_x[i] = (160<<16)+(x-160)*65000;
    table_y[i] = (100<<16)+(y-100)*65000;
    if(table_x[i]<0) table_x[i]=0;
    if(table_x[i]>(319<<16)) table_x[i]=(319<<16);
    if(table_y[i]<0) table_y[i]=0;
    if(table_y[i]>(199<<16)) table_y[i]=(199<<16);
    i++;
  }
}

void make_table_2 (void)
{
  int x,y,i;
  i=0;
  for (y=0; y<200; y++)
  for (x=0; x<320; x++)
  {
    float xx = (x-160);
    float yy = (y-100);
    float dist = sqrt (xx*xx+yy*yy)*0.0002;
    float s = sin(dist)*0.99;
    float c = cos(dist)*0.99;

    table_x[i] = (160.0+ xx * c - yy * s)*65536.0;
    table_y[i] = (100.0+ yy * c + xx * s)*65536.0;
    if(table_x[i]<0) table_x[i]=0;
    if(table_x[i]>(319<<16)) table_x[i]=(319<<16);
    if(table_y[i]<0) table_y[i]=0;
    if(table_y[i]>(199<<16)) table_y[i]=(199<<16);
    i++;
  }
}

void graphic (int on)
{
  // system dependent.. this turns on 320x200x8bit under dos
  int n;
  if ( on )
  {
    _asm {
      mov eax, 13h
      int 10h
    }
    outp (0x3c8, 0);
    for ( n=0; n<256; n++ )
    {
      outp (0x3c9, n>>2);
      outp (0x3c9, n>>2);
      outp (0x3c9, n>>2);
    }
  } else {
    _asm {
      mov eax, 3h
      int 10h
    }
  }
}

void blit (char * source)
{
  // system dependent.. this shows the picture.
  memcpy ((char *) 0xa0000, source, 320*200);
}



void main (void)
{
  char ch;
  int n;
  float t=0;
  memset (buf1, 0, 320*240);

//  make_table ();   // zoom effect
  make_table_2 (); // rotation effect..
  graphic (1);

  ch=0;
  do
  {
    // draw some lisajous dots
    // makes sure there is something to feedback..
    for ( n=0; n<100; n++ )
    {
      int x,y;
      float tt = t + 3.14*(float)n/100.0;
      x=160+80.0*sin(tt*3.0);
      y=100+50.0*cos(tt*2.3);
      buf1[320*y+x]=255;
    }
    t+=0.05;
    render (buf2, buf1);
    blit (buf2);
    memcpy (buf1, buf2, 320*200);
  } while ( !kbhit() );

  graphic (0);
}
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.