[SOLVED] what's wrong with that algorithm???

Started by Monsieur OUXX, Mon 08/07/2013 16:13:20

Previous topic - Next topic

Monsieur OUXX

OK, I'm sorry to post that here, but I'm going crazy over this.
It must be something obvious, but I keep looking at that script and fail to spot the obvious mistake.

It's a script to render a character onto a background pixel by pixel, with a little twist: there's also a surface used as a mask, to decide if the pixel is copied.

i and j iterate on every pixel of the mask surface, and then I look up what pixel from the character should be drawn (only if both the pixel from the mask and the pixel from the character are non-transparent). The pixel matching (i,j) in the "mask" surface has coordinates (x_on_char, y_on_char) in the character sprite.

There's also a perspective correction: E.g. depending on where "player" is standing, y_on_char gets altered by perspective_correction_y.

That's about it.
Here's the script: (I'm hiding it because it's full of unnecessary bullshit)
Spoiler

Code: AGS

  int color_char;
  int color_mirror;
  DrawingSurface* ds_mirror = data[mir_index].obj_spr.GetDrawingSurface();
  
  int i=0; int j=0;
   while (j<data[mir_index].height) //iterate on every pixel row in the mirror object
  {
    i=0;
    
   while (i<data[mir_index].width) //iterate on every pixel column in the mirror object   
    {
      color_mirror = ds_mirror.GetPixel(i, j);
      if (color_mirror!=data[mir_index].TRANSP_COLOR)
      {
        /*
        #define x_on_screen   x+i
        #define y_on_screen   y+j

        #define  x_correction  (-data[mir_index].x_offset) 
        #define  y_correction  (-data[mir_index].y_offset) 
        */
        
        int x_on_screen =  x+i;
        int y_on_screen = y+j;
        
        x_in_char = x_on_screen-frameData.x;
        y_in_char = y_on_screen-frameData.y;

        if (frameData.flipped)
          x_in_char = frameData.w - x_in_char;
          
        x_in_char = x_in_char /*+x_correction*/ +perspective_correction_x;
        y_in_char = y_in_char /*+y_correction*/ +perspective_correction_y/*+ofs*/;

        //Status.Text=String.Format("persp=%d",perspective_correction_y);//DEBUG
        
        if (     x_in_char>=0 && x_in_char<frameData.w 
              && y_in_char>=0 && y_in_char<frameData.h)
        {

          color_char = char_ds.GetPixel(x_in_char, y_in_char);
          
          if (     color_char!=frameData.TRANSP_COLOR )
          {
            ds.DrawingColor = color_char;
            ds.DrawPixel(x_on_screen,   y_on_screen);
          }
        }
        
      }
      
      i++;
    }
    j++;
  }

[close]

But now, here's the problem:
The script works OK, except perspective_correction_y doesn't seem to change.

As you can see, in the loop I even display its value into "status.Text". Thanks to that, I can see that when the character moves around, the value of perspective_correction_y increases and decreases as expected...
...BUT the rendered pixels stay in the same place on the screen. No matter how perspective_correction_y varies, the final value of  y_on_screen stays the same. The rendered character copy stays on the same horizontal line.

Where do I screw up the overwriting of my variables values? Or do I have two variables cancelling each other? I just fail to see it... It's driving me mad :D


 

Gilbert

Where are the codes that set/modify the values of perspective_correction_x/y?
They're just used in the attached script but there is no indication on how they're changed.

Crimson Wizard

I sorta have suspicion that you are applying corection to the wrong variable:

Code: ags

x_in_char = x_in_char /*+x_correction*/ +perspective_correction_x;
y_in_char = y_in_char /*+y_correction*/ +perspective_correction_y/*+ofs*/;


Shouldn't that be:

Code: ags

x_on_screen = x_on_screen  /*+x_correction*/ +perspective_correction_x;
y_on_screen = y_on_screen  /*+y_correction*/ +perspective_correction_y/*+ofs*/;

Monsieur OUXX

Quote from: Iceboty V7000a on Mon 08/07/2013 17:31:38
Where are the codes that set/modify the values of perspective_correction_x/y?
They're just used in the attached script but there is no indication on how they're changed.
They're calculated once before the loop.
The thing is, it doesn't really matter, because as I said I can see in Status.Text (on-screen) that the value is varying correctly; As you can see I dump perspective_correction_y into Status.Text right in the middle of the loop, where it's critical that the value is correct. And it is correct.

Quote from: Crimson Wizard on Mon 08/07/2013 17:45:10
shouldn't you be setting x_on_screen instead of x_in_char?
The principle of the algorithm is that I start from the pixel on-screen, and calculate what pixel in the character sprite it should display. Therefore, x_on_screen (resp. y_on_screen) must always be x+i (resp. y+j).
But I can change the calculations of x_in_char/y_in_char to pick a different pixel from the character sprite. That's where the corrections steps in.

 

Khris

#4
Just a thought, and it's quite possibly BS, but maybe not: what if while the editor correctly colors the comments and code parts, due to some quirk, the compiler reads /* bla */ bli /* blu */ as /* bla bli blu */ in line 33?

Edit: Scratch that. Tested it and it compiles as indicated.

Crimson Wizard

#5
Quote from: Monsieur OUXX on Mon 08/07/2013 23:13:27
The principle of the algorithm is that I start from the pixel on-screen, and calculate what pixel in the character sprite it should display. Therefore, x_on_screen (resp. y_on_screen) must always be x+i (resp. y+j).
But I can change the calculations of x_in_char/y_in_char to pick a different pixel from the character sprite. That's where the corrections steps in.

Well, In this case I don't understand.

Earlier you said:
Quote
No matter how perspective_correction_y varies, the final value of  y_on_screen stays the same

But I can't see why y_on_screen should depend on perspective_correction_y at all. There's no operation that would refer these two variables at once.

Khris

As far as I understand, x/y_in_char and x/y_on_screen have a fixed relation:
Code: ags
        int x_on_screen =  x+i;
        int y_on_screen = y+j;
       
        x_in_char = x_on_screen-frameData.x;
        y_in_char = y_on_screen-frameData.y;

So regardless of other values, on_screen is offset from in_char by constant values.

The perspective correction should alter that fixed offset, but only does so on the x-axis. Doesn't really matter which pair of coordinates is used where, right?

The only thing that's left really is this: where are you drawing the surface? I assume it's drawn at a fixed position, the mirror's position on the background, right? Or are you maybe offsetting it, too?

Monsieur OUXX

#7
Quote from: Crimson Wizard on Mon 08/07/2013 23:22:16
Earlier you said:
Quote
No matter how perspective_correction_y varies, the final value of  y_on_screen stays the same
But I can't see why y_on_screen should depend on perspective_correction_y at all. There's no operation that would refer these two variables at once.

Hmmmm... I don't understand and I don't see how to explain further.

Imagine this algorithm as this :
- I choose a sort of "window" on the screen, that goes from (x,y) to (x+data[mir_index].width, y+data[mir_index].height).
- I iterate within that rectangular window using i and j.
- At any given time, the screen coordinate of the pixel being drawn is: (x+i, y+j). That's the same as (x_on_screen, y_on_screen)

Now, you want to decide what color must be drawn at (x_on_screen, y_on_screen):
- If I was just copying the source sprite to the top-left corner of my window, I'd pick the pixel at (x_in_char, y_in_char) ...with x_in_char=i and y_in_char=j.
- Now imagine I want to copy the source sprite in the exact place where the playable character is standing : I'd use x_in_char=i+(x_on_screen-player.left), y_in_char=j+(y_on_screen-player.top). (note: player.left and player.top don't exist in AGS, they need to be calculated from player.x and player.y).
- Now imagine you want to copy the source sprite 10 pixels higher than where the player is standing. I'd use x_in_char=i+(x_on_screen-player.left), y_in_char=j+(y_on_screen-player.top+10). You see? I'm not changing y_on_screen, but by increasing y_in_char I make the sprite being rendered higher on-screen. It's all shifted upwards.
- Now imagine you replace this "+10" with perspective_correction_y. If you need to know, it's calculated on the distance between the player and a given point on the screen. The more the player walk away from that point, the more perspective_correction_y increases.
=>  The consequence should be that the copied sprite gets drawn "higher" on-screen. But it's not. The algorithm works OK, which means when the player walks left and right, then the copied sprite follows left and right -- but when the player also walks up and down, even though perspective_correction_y changed accordingly, then the copied sprite moves left and right but stays on the same horizontal line.
 

Monsieur OUXX

Quote from: Khris on Mon 08/07/2013 23:30:36
The perspective correction should alter that fixed offset, but only does so on the x-axis.

Why do you say that?
Two lines below the lines, you quoted, I add perspective_correction_y to y_in_char.
 

Khris

I was answering Crimson Wizard, trying to explain the problem in relation to what he thought about it.

geork

#10
[For debugging purposes, you could try copying the mask image to the mirror object every loop instead of at the end (with a display function somewhere), to see how the image is built up.] - EDIT: Sorry, I just realized it wouldn't make a difference...

Other than that, the only explanation I can see is what Khris has already pointed out - that the mask image is drawn onto the mirror object at an oppositely transposed y position...

Monsieur OUXX

Oh my god the issue was so freakin simple, I can't believe it.

Adding perspective_correction_y to x_in_char was just enough to target the correct pixel in the character sprite without any change. It was making sure that the distance between the char and the bottom of the mirror was taken in account. Therefore the character sprite was rendered into the mask as if the character wasn't moving (that was my problem).

But I had to add ANOTHER perspective_correction_y to make sure that when the character walks away from the mirror, then the reflection moves up symmetrically.

All I had to do was to change
Code: AGS
y_in_char = y_in_char +perspective_correction_y;

to
Code: AGS
y_in_char = y_in_char +2*perspective_correction_y;


...As always, that was a silly case of "I've been looking at this script for too long".

Hurray!
There's a nice little Mirrors module coming.

 

SMF spam blocked by CleanTalk