copying a pixel and pasting it in another location

Started by Kimbra, Sun 27/05/2012 12:57:44

Previous topic - Next topic

Kimbra

can I copy a pixel at x1y1 and paste it in x2y2?

Khris

Sure, just get the relevant DrawingSurface, then call its GetPixel and DrawPixel functions.

Code: ags
  DrawingSurface*ds = Room.GetDrawingSurfaceForBackground();
  ds.DrawingColor = ds.GetPixel(1, 1);
  ds.DrawPixel(2, 2);

Kimbra

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?

Khris

Yes, just do this:
Code: ags
  DynamicSprite*temp = DynamicSprite.CreateFromScreenShot();
  DrawingSurface*ds = temp.GetDrawingSurface();
  ...


monkey0506

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.

Kimbra

now it won't work...
this is my code from [ room_RepExec() ] :
Code: AGS
  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?

Khris

You have to release the surface after drawing to it.
Just add this line:
Code: ags
  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
    int mi = mouse.GetModeGraphic(eModeWait);
    mouse.ChangeModeGraphic(eModeWait, 0);
    Wait(1);
    DynamicSprite*ds = DynamicSprite.CreateFromScreenShot();
    mouse.ChangeModeGraphic(eModeWait, mi);
    ds.SaveToFile("screenshot.pcx");

Kweepa

Alternatively, depending on how complicated your scene is:
If it's just non-transparent unscaled objects and sprites (no walkbehinds)
Code: AGS

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.
Still waiting for Purity of the Surf II

Kimbra

I tried adding the Release() command and it is still not working, this is my code:

Code: AGS
  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()?

SSH

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

Kimbra

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!

Kweepa

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.
Still waiting for Purity of the Surf II

monkey0506

#12
Quote from: Kweepa on Sun 27/05/2012 19:57:33
Code: AGS

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

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

Kimbra

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

Khris

Alright, in that case you need to switch to a different DrawingSurface. Try this:

Code: ags
  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.

Kimbra

It worked! Thanks Khris! I'll see what I can do to solve the cursor problem :)

thanks all!

Ryan Timothy B

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.

SMF spam blocked by CleanTalk