Adventure Game Studio

AGS Support => Advanced Technical Forum => Topic started by: Kimbra on Sun 27/05/2012 12:57:44

Title: copying a pixel and pasting it in another location
Post by: Kimbra on Sun 27/05/2012 12:57:44
can I copy a pixel at x1y1 and paste it in x2y2?
Title: Re: copying a pixel and pasting it in another location
Post by: Khris on Sun 27/05/2012 13:09:37
Sure, just get the relevant DrawingSurface, then call its GetPixel and DrawPixel functions.

Code (ags) Select
  DrawingSurface*ds = Room.GetDrawingSurfaceForBackground();
  ds.DrawingColor = ds.GetPixel(1, 1);
  ds.DrawPixel(2, 2);
Title: Re: copying a pixel and pasting it in another location
Post by: Kimbra on Sun 27/05/2012 16:40:48
why thank you Khris!
but it worked exactly as I wasn't anticipating :(
let me elaborate:
I don't want to copy a pixel from the room's background only, I want to copy what ever pixel is currently displayed at xy
so it could also be from a sprite drawn on the same xy.
maybe as if the copied xy is taking from a screen capture instead?
Title: Re: copying a pixel and pasting it in another location
Post by: Khris on Sun 27/05/2012 17:20:39
Yes, just do this:
Code (ags) Select
  DynamicSprite*temp = DynamicSprite.CreateFromScreenShot();
  DrawingSurface*ds = temp.GetDrawingSurface();
  ...

Title: Re: copying a pixel and pasting it in another location
Post by: monkey0506 on Sun 27/05/2012 17:40:31
There is one potential problem with CreateFromScreenShot in that it includes the mouse cursor, which probably wouldn't be what you would want. There's not really an easy/simple alternative - you basically have to redraw the entire screen yourself to get around it.
Title: Re: copying a pixel and pasting it in another location
Post by: Kimbra on Sun 27/05/2012 18:33:48
now it won't work...
this is my code from [ room_RepExec() ] :
Code (AGS) Select
  DynamicSprite*temp = DynamicSprite.CreateFromScreenShot();
  DrawingSurface*ds = temp.GetDrawingSurface();
  ds.DrawingColor = ds.GetPixel(226, 262);
  ds.DrawPixel(2, 2);


I read in the manual that such commands would slow down the game, but I'm sure it won't run wrong.

and yes I wouldn't wanna draw pixels captured from mouse cursors! you said there is no simple solution for that, can you try me with more advanced brain itching material?
Title: Re: copying a pixel and pasting it in another location
Post by: Khris on Sun 27/05/2012 18:49:02
You have to release the surface after drawing to it.
Just add this line:
Code (ags) Select
  ds.Release();

I managed to make a screenshot without the mouse cursor, that included a Wait(1); though and isn't suitable for room_RepExec:
Code (ags) Select
    int mi = mouse.GetModeGraphic(eModeWait);
    mouse.ChangeModeGraphic(eModeWait, 0);
    Wait(1);
    DynamicSprite*ds = DynamicSprite.CreateFromScreenShot();
    mouse.ChangeModeGraphic(eModeWait, mi);
    ds.SaveToFile("screenshot.pcx");
Title: Re: copying a pixel and pasting it in another location
Post by: Kweepa on Sun 27/05/2012 19:57:33
Alternatively, depending on how complicated your scene is:
If it's just non-transparent unscaled objects and sprites (no walkbehinds)
Code (AGS) Select

int get_color_at_simple(int x, int y)
{
  int col;
  Object *o = Object.GetAtScreenXY(x, y);
  if (o != null)
  {
    int graphic = object[o.ID].Graphic;
    DynamicSprite *ds = DynamicSprite.CreateFromExistingSprite(graphic);
    DrawingSurface *surf = ds.GetDrawingSurface();
    col = surf.GetPixel(x - o.X, y - o.Y);
    surf.Release();
    ds.Delete();
  }
  else
  {
    Character *c = Character.GetAtScreenXY(x, y);
    if (c != null)
    {
      ViewFrame *frame = Game.GetViewFrame(character[c.ID].View, character[c.ID].Loop, character[c.ID].Frame);
      int graphic = frame.Graphic;
      DynamicSprite *ds = DynamicSprite.CreateFromExistingSprite(graphic);
      if (frame.Flipped)
      {
        ds.Flip(eFlipLeftToRight);
      }
      DrawingSurface *surf = ds.GetDrawingSurface();
      col = surf.GetPixel(x - c.x - Game.SpriteWidth[graphic]/2, y - c.y - Game.SpriteHeight[graphic]/2 + c.z);
      surf.Release();
      ds.Delete();
    }
    else
    {
      DrawingSurface *surf = Room.GetDrawingSurfaceForBackground();
      col = surf.GetPixel(x, y);
      surf.Release();
    }
  }
  return col;
}


If it's the whole shebang, try this module:
http://www.kweepa.com/step/ags/tech/FakeScreen.scm
This extracts walkbehinds at room startup (takes a second), and then recomposites the entire screen on demand.
You need to have an extra object 0 and walkbehind covering everything.
It doesn't yet work with scrolling rooms unfortunately.
Title: Re: copying a pixel and pasting it in another location
Post by: Kimbra on Mon 28/05/2012 07:43:35
I tried adding the Release() command and it is still not working, this is my code:

Code (AGS) Select
  DynamicSprite*temp = DynamicSprite.CreateFromScreenShot();
  DrawingSurface*ds = temp.GetDrawingSurface();
  ds.DrawingColor = ds.GetPixel(226, 262);
  ds.DrawPixel(2, 2);
  ds.Release();


I will try Kweepa's method and let you know if it works. Still, I can't see why the above method won't work! Khris have you tested it? Could it be due to its location in Rep_Exec()?
Title: Re: copying a pixel and pasting it in another location
Post by: SSH on Mon 28/05/2012 08:49:40
What are you doing with the Dynamic Sprite after that code snippet? If nothing, then there won't be any effect, as you'd need to draw the modified pixel on to something... a GUI, object, background...
Title: Re: copying a pixel and pasting it in another location
Post by: Kimbra on Mon 28/05/2012 10:30:12
are you suggesting a line before the Release() command?

I'm just trying to duplicate a pixel somewhere in the background from another one whether it is copied from a sprite or the background (except cursors). And to top all that, I'd love to make it happening during game play, so if my ship (player character) or enemy ships (objects) moved over that specific xy, it copies the pixels from their sprites to display it somewhere else.

Thanks for all your help in advance!
Title: Re: copying a pixel and pasting it in another location
Post by: Kweepa on Mon 28/05/2012 14:22:30
What GENERALLY are you trying to do? If this is for a special effect, could you describe it roughly? On a larger scale than "copy pixel x,y to p,q". That would help.
Title: Re: copying a pixel and pasting it in another location
Post by: monkey0506 on Mon 28/05/2012 15:12:59
Quote from: Kweepa on Sun 27/05/2012 19:57:33
Code (AGS) Select

    // this line...
    int graphic = object[o.ID].Graphic;
    // and this one...
      ViewFrame *frame = Game.GetViewFrame(character[c.ID].View, character[c.ID].Loop, character[c.ID].Frame);

...they made me laugh. Come on Steve, why are you referencing global arrays of Object*s and Character*s by using the ID properties of an Object* and Character*? :P

Code (AGS) Select

  int graphic = o.Graphic;
  frame = Game.GetViewFrame(c.View, c.Loop, c.Frame);


Anyway, you're actually right, then I didn't think about specializing the code to the particular situation, partly because I didn't know exactly what he wanted to do. One thing that you could utilize would be to check the mouse coordinates as well as GetLocationType. If the mouse coordinates don't intersect with that particular area, then you could reasonably use CreateFromScreenShot. Otherwise you could extrapolate the Character/Object position based on the LocationType of the given coordinates, then you could include scaling and flipped frames. Partial transparency would complicate matters, but it wouldn't be unfeasible.

I've pointed it out before, but making the scaling/flipped sprites easier:

Code (AGS) Select
DynamicSprite *sprite = null;
int graphic = frame.Graphic;
if (c.Scaling != 100)
{
  sprite = DynamicSprite.CreateFromExistingSprite(graphic);
  sprite.Resize((Game.SpriteWidth[graphic] * c.Scaling) / 100, (Game.SpriteHeight[graphic] * c.Scaling) / 100);
  graphic = sprite.Graphic;
}
if (frame.Flipped)
{
  if (sprite == null) sprite = DynamicSprite.CreateFromExistingSprite(graphic);
  sprite.Flip(eFlipLeftToRight);
  graphic = sprite.Graphic;
}
// use the graphic
if (sprite != null)
{
  sprite.Delete();
  sprite = null;
}


That way you don't create an unnecessary DynamicSprite, and only call the Resize/Flip functions if they're actually needed.
Title: Re: copying a pixel and pasting it in another location
Post by: Kimbra on Mon 28/05/2012 17:21:14
this is the simplest way I can put it:

I want whatever on the coordinates (226, 262) to be displayed on the coordinates (2, 2) simultaneously.
this location (226, 262) is on a walkable area, meaning, it must carry either a background pixel, a moving sprite of a character or an object passing by.
I'd want to put it in the room's Rep_Exec to catch live actions (moving sprites over the location)...

the best hypothetical solution I can come up with, is taking a screen shot of the room with all its sprites (no cursors) then copy the pixel information and draw it on the desired location.
I'll try every single code line you guys wrote and let you know, thanks!!!!
Title: Re: copying a pixel and pasting it in another location
Post by: Khris on Mon 28/05/2012 22:10:33
Alright, in that case you need to switch to a different DrawingSurface. Try this:

Code (ags) Select
  DynamicSprite*temp = DynamicSprite.CreateFromScreenShot();
  DrawingSurface*ds = temp.GetDrawingSurface();
  int color = ds.GetPixel(226, 262);
  ds.Release();
  temp.Delete();
  ds = Room.GetDrawingSurfaceForBackground();
  ds.DrawingColor = color;
  ds.DrawPixel(2, 2);
  ds.Release();

Note that this doesn't take care of the cursor problem, but it should be sufficient to get you started.
Title: Re: copying a pixel and pasting it in another location
Post by: Kimbra on Tue 29/05/2012 18:32:47
It worked! Thanks Khris! I'll see what I can do to solve the cursor problem :)

thanks all!
Title: Re: copying a pixel and pasting it in another location
Post by: Ryan Timothy B on Tue 29/05/2012 19:02:12
The only way to get around the cursor issue or a GUI being grabbed is to draw the scene yourself. Iterate through all the objects and characters and draw them to the screen depending on their baseline. Unless someone makes a TakeGameGraphicShot function in the engine that takes a DynamicSprite of the game screen before sandwiching the GUI's and cursor to the game screen.