Drawing on screen (PLUGIN) [SOLVED]

Started by Dualnames, Tue 12/02/2019 21:10:43

Previous topic - Next topic

Dualnames

Code: ags

//WIND ENGINE

struct Particle{
int x;
int y;
int transp;
int life;
bool active;
int dx;
int dy;
int mlay;
int timlay;
int movedport;
int translay;
int translayHold;
int width;
int height;
int fx;
int fy;
bool doingcircle;
float angle;
float radius;
int doingCircleChance;
int angleLay;
int frame;
float anglespeed;
};

Particle particles[110];
Particle particlesF[10];
int WForceX[110];
int WForceY[110];

int raysizeF=4; 
int dsizeF=0;
int raysize=100; 
int dsize=0;
int creationdelay=0;
int creationdelayf=0;
bool found_Activeparticle=false;

int32 Random(int value)
{
	return (rand() % value);
}

void CreateParticle(int xx, int yy, int ForceX, int ForceY)
{
  int h=0;
  bool foundparticle=false;
  int fid=-1;
  while (h <= dsize && !foundparticle)
  {
    if (particles[h].active==false)
    {
      foundparticle=true;
      fid=h;
    }
    h++;
  }
  
  if (foundparticle)
  {
    int d=fid;
    particles[d].x=xx;
    particles[d].y=yy;
    particles[d].dx=0;
    particles[d].dy=0;
    particles[d].life=20000;
    particles[d].transp=55+Random(10);
    particles[d].active=true;
    particles[d].mlay=4+Random(2);
    particles[d].timlay=0;
    particles[d].translay=0;
    particles[d].translayHold=19+Random(15);
    particles[d].width=2+Random(2);
    particles[d].height=particles[d].width;
    particles[d].fx=0;
    particles[d].fy=0;
    particles[d].doingcircle=false;
    particles[d].angle=0.0;
    particles[d].radius=4.0+float(Random(6));
    particles[d].doingCircleChance=Random(200);
    particles[d].angleLay=0;
    particles[d].frame=0;
    particles[d].anglespeed=float(Random(20))/100.0;
    WForceX[d]=ForceX;
    WForceY[d]=ForceY;
    if (dsize<(raysize-1)) dsize++;
  }
}



void CreateParticleF(int xx, int yy, int ForceX, int ForceY)
{
  int h=0;
  bool foundparticle=false;
  int fid=-1;
  while (h <= dsizeF && !foundparticle)
  {
    if (particlesF[h].active==false)
    {
      foundparticle=true;
      fid=h;
    }
    h++;
  }
  
  if (foundparticle)
  {
    int d=fid;
    particlesF[d].x=xx;
    particlesF[d].y=yy;
    particlesF[d].dx=(-1)+Random(1);
    particlesF[d].dy=(-1)+Random(1);
    particlesF[d].life=20000;
    particlesF[d].transp=45+Random(10);
    particlesF[d].active=true;
    particlesF[d].mlay=4+Random(2);
    particlesF[d].timlay=0;
    particlesF[d].translay=0;
    particlesF[d].translayHold=19+Random(15);
    particlesF[d].width=8+Random(2);
    particlesF[d].height=particlesF[d].width;
    particlesF[d].fx=0;
    particlesF[d].fy=0;
    particlesF[d].doingcircle=false;
    particlesF[d].angle=0.0;
    particlesF[d].radius=4.0+float(Random(6));
    particlesF[d].doingCircleChance=Random(200);
    particlesF[d].angleLay=0;
    WForceX[d+100]=ForceX;
    WForceY[d+100]=ForceY;
    particlesF[d].frame=0;
    
    
    if (dsizeF<(raysizeF-1)) dsizeF++;
  }
}

//WIND ENGINE

///WING ENGINE UPDATE
void ParticleUpdate(int ForceX, int ForceY, int Transparency,int RoomWidth,int RoomHeight)
{
  
  int ww=RoomWidth;
  int hh=RoomHeight;
  BITMAP* screen = engine->GetVirtualScreen();

  found_Activeparticle=false;
  creationdelay+=int(2.0);
  if (creationdelay > 0)
  {   
    
    int by=0;
    while (by <2)
    {
    int dnx=Random(ww+250)-250;
    int dny=Random(hh);    
    CreateParticle(dnx, dny, ForceX, ForceY);
    by++;
    }
    
    int dnx=-(20+Random(50));
    if (dnx<-160) dnx=-160;
    if (dnx > ww+160) dnx=ww+160;
    
    int dny=Random(hh);    
    CreateParticleF(dnx, dny, ForceX, ForceY);
    
    found_Activeparticle=true;
    
    creationdelay=0;
  }
  
  int h=dsize-1;
  
  if (h < dsizeF-1)
  {
    h=dsizeF-1;
  }
  while (h>0)
  {
    if (particles[h].life>0)
    {
      found_Activeparticle=true;
      particles[h].life-=int(2.0);
      particles[h].doingCircleChance-=1;
      int df=100-particles[h].transp;
      df=10-(df/4);
      int pwidth=particles[h].width+df;
      int pheight=particles[h].height+df;
      
      int px=particles[h].x-(pwidth/2);
      int py=particles[h].y-(pheight/2);
      int tp=particles[h].transp+Transparency;
      
      if (tp>100) tp=100;
      
      int pgraph=0;
      int SplitBetweenTwo=Random(100);
      if (SplitBetweenTwo<=50) pgraph=813;
      else pgraph=4466;
      
      if (tp!=100)
	  {
		  BITMAP* ParticleGraph = engine->GetSpriteGraphic(pgraph+particles[h].frame);
		  engine->BlitSpriteTranslucent(px, py, ParticleGraph,tp);
		  //drawt.DrawImage(px, py, pgraph+particles[h].frame, tp, pwidth, pheight);
	  }
      particles[h].timlay+=int(4.0);
      if (particles[h].timlay> particles[h].mlay)
      {
        particles[h].frame++;
        if (particles[h].frame>6) particles[h].frame=0;
        particles[h].timlay=0;
        particles[h].x += particles[h].dx+particles[h].fx; 
        particles[h].y += particles[h].dy+particles[h].fy;      
      }
      particles[h].translay+=1;
      if (particles[h].translay>=particles[h].translayHold)
      {
        if (particles[h].transp<=99) particles[h].transp++;
        else 
        {
          particles[h].life=0;
          found_Activeparticle=false;
        }
      }
      if (particles[h].x>=ww-90 || particles[h].x<90)
      {
        if (particles[h].transp<=99)particles[h].transp++;
        else 
        {
          found_Activeparticle=false;
          particles[h].life=0;       
        }
      }
      
      if (!particles[h].doingcircle && particles[h].angle==0.0
      && particles[h].doingCircleChance<=0)
      {
        particles[h].doingcircle=true;
      }
      if (particles[h].doingcircle)
      {
        particles[h].angleLay+=(1+WForceX[h]);
        if (particles[h].angleLay> 12)
        {
          particles[h].angleLay=0;
          particles[h].angle+=particles[h].anglespeed;
          int Y=particles[h].y + int((sin(particles[h].angle)* particles[h].radius));
          int X=particles[h].x + int((cos(particles[h].angle)* particles[h].radius));
          particles[h].x=X;
          particles[h].y=Y;  
        }
      }
      particles[h].fx=ForceX;
      particles[h].fy=ForceY;
      
    }
    else 
    {
      particles[h].active=false;
    }
    
    
    
    if (h<=9 && particlesF[h].life>0)
    {
      found_Activeparticle=true;
      int pwidth=particlesF[h].width;
      int pheight=particlesF[h].height;
      int px=particlesF[h].x-(pwidth/2);
      int py=particlesF[h].y-(pheight/2);
      int pgraph=0;
      int SplitBetweenTwo=Random(100);
      if (SplitBetweenTwo<=50) pgraph=806;
      else pgraph=4459;
      
      int tp=particlesF[h].transp+Transparency;      
      if (tp>100) tp=100;
      
      
      if (tp!=100)
	  {
		  BITMAP* Particle_B = engine->GetSpriteGraphic(pgraph+particlesF[h].frame);
		  engine->BlitSpriteTranslucent(px, py, Particle_B,tp);
		  //drawt2.DrawImage(px, py, pgraph+particlesF[h].frame, tp, pwidth, pheight);
	  }
      particlesF[h].timlay+=int(4.0);
      if (particlesF[h].timlay> particlesF[h].mlay)
      {
        particlesF[h].frame++;
        if (particlesF[h].frame>6)  particlesF[h].frame=0;
        particlesF[h].timlay=0;
        particlesF[h].x += particlesF[h].dx + ForceX;
        particlesF[h].y += particlesF[h].dy + ForceY;  
      }
      
      
      if (particlesF[h].x>=ww-90 || particlesF[h].x<90)
      {
        particlesF[h].translay+=1; 
        if (particlesF[h].translay>=particlesF[h].translayHold)
        {          
          if (particlesF[h].transp<=99) particlesF[h].transp++;
          else 
          {
            found_Activeparticle=false;
            particlesF[h].life=0;
          }
        }
      }      
    }
    else 
    {
      if (h<=9)  particlesF[h].active=false;
    }
    
    
    h--;
  }
  engine->ReleaseBitmapSurface(screen);
  
}

//WIND ENGINE UPDATE



Nothing seems to be drawing on the screen, on my AGS script side i just run ParticleUpdate(int ForceX, int ForceY, int Transparency,int RoomWidth,int RoomHeight).
This is 'replacement' code moved from AGS to the plugin, so the code itself works fine. Any thoughts on why it doesn't? I'm not sure I'm using the 'virtual screen' part correctly, but there's little to no examples, I could find for it. Apologies for the sequence of new posts every day.
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Crimson Wizard

#1
What version of AGS are you using? Drawing to VirtualScreen did not work for Direct3D and OpenGL before AGS 3.4.1. It was also proven to work somewhat slower for non-software driver in 3.4.1 and later (depending on game resolution), because it's not an optimal way for these renderers.

Secondly, AFAIK you should not call plugin drawing to screen directly from AGS script, but instead connect to AGS drawing hook.

Since your ParticleUpdate function has both update and draw, and if you really must explicitly call update from the script, it should be split into Update/Draw parts. Update may be called from script, but Draw must be connected to the drawing event.

You may refer to snow rain plugin source, for example the one in our repository: https://github.com/adventuregamestudio/ags/blob/master/Plugins/ags_snowrain/ags_snowrain.cpp

Points of interest:

engine->RequestEventHook(AGSE_PREGUIDRAW); // this asks AGS to call you right after room finished drawing but before GUI is drawn

int AGS_EngineOnEvent(int event, int data) // this is the event callback function

Dualnames

#2
You are correct now it's properly hooked, it needed SetVirtualScreen at the end as well. So question

Code: ags

BITMAP* ParticleGraph = engine->GetSpriteGraphic(pgraph+particles[h].frame);
engine->BlitSpriteTranslucent(px, py, ParticleGraph,tp);
//drawt.DrawImage(px, py, pgraph+particles[h].frame, tp, pwidth, pheight);


This part i want it to scale the sprite to width PWIDTH and height PHEIGHT, before blitspriting it onto the screen, what commands are there for that?

Edit:
Code: ags

BITMAP* ParticleGraph = engine->GetSpriteGraphic(pgraph+particles[h].frame);
int32 w, h, d;
engine->GetBitmapDimensions(Particle_B, &w, &h, &d);
w=pwidth;
 h=pheight;
engine->ReleaseBitmapSurface(Particle_B);
engine->BlitSpriteTranslucent(px, py, ParticleGraph,tp);


Is that the right way?
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Dualnames

I'm also looking for a command that clears the virtual screen, so that i can use that before accessing it.
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Crimson Wizard

#4
Quote from: Dualnames on Tue 12/02/2019 21:39:20
it needed SetVirtualScreen at the end as well.

Could you explain what the plugin is doing in a nutshell?

SetVirtualScreen only really works in Software mode. It replaces the drawing surface for all the following drawing in the engine. Direct3D and OpenGL drivers will never be able to use it since they don't draw to screen bitmap.

Normally plugins that want to draw something on screen call GetVirtualScreen instead to ask engine for a current stage surface (there are several stages, one for room, another for GUI and so on) and draw your own image to that. Then it will be inserted on AGS screen in between the stages (e.g. between room and GUI).

But if you want to read from what's already drawn on screen, this will generally work only in software mode. I cannot think of an easy way to make it work for hardware-accelerated renderers. Normally they should use shaders.


Quote from: Dualnames on Tue 12/02/2019 22:18:04
I'm also looking for a command that clears the virtual screen, so that i can use that before accessing it.

I don't remember if there's plugin function for that, but you may call GetRawBitmapSurface to get bitmap's data pointer and fill its contents with zeroes.

Dualnames

The plugin is drawing particles on the screen. It's a wind effect.

What it does is it draws sprites on the screen, altering their size, their position and their transparency.
In the equivalent of the AGS script, every x loops a sprite is created, then parsing through all the existing particles (flagged with ACTIVE) it moves them based on a force (X and Y) and adjusts their size and transparency.
Then clears the screen and on the next loop it repeats the same processt.

Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Crimson Wizard

#6
Quote from: Dualnames on Tue 12/02/2019 22:27:57
The plugin is drawing particles on the screen. It's a wind effect.

What it does is it draws sprites on the screen, altering their size, their position and their transparency.
In the equivalent of the AGS script, every x loops a sprite is created, then parsing through all the existing particles (flagged with ACTIVE) it moves them based on a force (X and Y) and adjusts their size and transparency.
Then clears the screen on the next loop, and redoes that.

Oh, so, you need to call GetVirtualScreen at the beginning of your drawing function. On software mode it will already contain everything drawn before that (like, the room and objects), but in D3D/OGL it will be a clean bitmap filled with transparent pixels (iirc).
Also for compatibility, call GetBitmapDimensions to know the actual size of the virtual screen's bitmap, because it may not be equal to game screen size.

You may then call BlitSpriteTranslucent which does suitable drawing depending on the render mode (software/hardware) internally.

You did not answer about version of AGS, so I have to restate that this refers to AGS 3.4.1 (in earlier versions only software mode will work correctly).

Dualnames

Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Dualnames

Mhh, i seemed to be unable to draw on a clean slate, like I want, I'm gonna try some stuff.
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Crimson Wizard

#9
Oh sorry, I made a mistake. You do not have to call GetVirtualScreen at all if you are using BlitSpriteTranslucent and similar functions, because these draw on virtual screen themselves.
You only need to get virtual screen pointer if you do drawing with your custom functions which edit bitmap data directly.


Quote from: Dualnames on Tue 12/02/2019 22:49:27
Mhh, i seemed to be unable to draw on a clean slate, like I want, I'm gonna try some stuff.

What exactly is happening? It's a bit tought to guess the problem.
Also, which renderer are you testing with? Results may differ (in case of mistakes too).

Dualnames

Where it's supposed to draw nothing aka draw fully transparent sprites, instead it's drawing static (non-moving) wind sprites.
Which makes me thing it's not pulling from an empty screen, but rather the version of the screen, one loop before.

I am using D3d9
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Dualnames

I've tried this as a means of clearing the virtual screen, but nope.
Code: ags

else if (event == AGSE_POSTSCREENDRAW)
  {
	  BITMAP* P = engine->GetVirtualScreen();
	  unsigned int32 **spriteMemRef = (unsigned int32 **)engine->GetRawBitmapSurface (P);
	  int x,y;
	  for (y = 0; y < screen_height; y++)
	  {
		  for (x = 0; x < screen_width; x++)
		  {
			  spriteMemRef[y][x]=0;
		  }
	 }
	 engine->ReleaseBitmapSurface(P);
	 engine->SetVirtualScreen(P);
  }
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Dualnames

Actually I figured out the slowdown on the modularized version, so i don't need to do this through a plugin!!
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Crimson Wizard

#13
Quote from: Dualnames on Tue 12/02/2019 23:14:25
I've tried this as a means of clearing the virtual screen, but nope.
Code: ags

else if (event == AGSE_POSTSCREENDRAW)
  {
	  BITMAP* P = engine->GetVirtualScreen();
	  unsigned int32 **spriteMemRef = (unsigned int32 **)engine->GetRawBitmapSurface (P);
	  int x,y;
	  for (y = 0; y < screen_height; y++)
	  {
		  for (x = 0; x < screen_width; x++)
		  {
			  spriteMemRef[y][x]=0;
		  }
	 }
	 engine->ReleaseBitmapSurface(P);
	 engine->SetVirtualScreen(P);
  }


Well, I keep telling that SetVirtualScreen does not work in D3D.
Also, you first GetVirtualScreen and then set it back, that does not make any sense.

Anyway, this code won't work as you think it does, because in every stage the virtual screen may be a different bitmap. So you are not clearing same bitmap you were drawing to.
On D3D the Virtual Screen is cleared automatically each time (at least supposed to).

Dualnames

Yeah, I'm sorry this is kinda new information and I'm bruteforcing it like a chimp :D
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

SMF spam blocked by CleanTalk